< prev index next >

src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp

Print this page

  1 /*
  2  * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  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
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "jfr/leakprofiler/chains/edgeStore.hpp"
 27 #include "jfr/leakprofiler/chains/edgeUtils.hpp"

 28 #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
 29 #include "oops/oop.inline.hpp"

 30 
 31 StoredEdge::StoredEdge(const Edge* parent, UnifiedOopRef reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
 32 
 33 StoredEdge::StoredEdge(const Edge& edge) : Edge(edge), _gc_root_id(0), _skip_length(0) {}
 34 
 35 StoredEdge::StoredEdge(const StoredEdge& edge) : Edge(edge), _gc_root_id(edge._gc_root_id), _skip_length(edge._skip_length) {}
 36 
 37 traceid EdgeStore::_edge_id_counter = 0;
 38 
 39 EdgeStore::EdgeStore() : _edges(NULL) {
 40   _edges = new EdgeHashTable(this);
 41 }
 42 
 43 EdgeStore::~EdgeStore() {
 44   assert(_edges != NULL, "invariant");
 45   delete _edges;
 46 }
 47 
 48 bool EdgeStore::is_empty() const {
 49   return !_edges->has_entries();
 50 }
 51 
 52 void EdgeStore::on_link(EdgeEntry* entry) {
 53   assert(entry != NULL, "invariant");
 54   assert(entry->id() == 0, "invariant");
 55   entry->set_id(++_edge_id_counter);
 56 }
 57 
 58 bool EdgeStore::on_equals(uintptr_t hash, const EdgeEntry* entry) {
 59   assert(entry != NULL, "invariant");
 60   assert(entry->hash() == hash, "invariant");
 61   return true;
 62 }
 63 
 64 void EdgeStore::on_unlink(EdgeEntry* entry) {
 65   assert(entry != NULL, "invariant");
 66   // nothing
 67 }

207 
208 bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t limit) {
209   assert(*previous != NULL, "invariant");
210   assert(*current != NULL, "invariant");
211   size_t depth = 1;
212   while (*current != NULL && depth < limit) {
213     StoredEdge* stored_edge = get((*current)->reference());
214     if (stored_edge != NULL) {
215       link_with_existing_chain(stored_edge, previous, depth);
216       return true;
217     }
218     stored_edge = link_new_edge(previous, current);
219     assert((*previous)->parent() != NULL, "invariant");
220     *previous = stored_edge;
221     *current = (*current)->parent();
222     ++depth;
223   }
224   return NULL == *current;
225 }
226 
227 // Install the immediate edge into the mark word of the leak candidate object















































































228 StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {
229   assert(edge != NULL, "invariant");
230   assert(!contains(edge->reference()), "invariant");
231   StoredEdge* const leak_context_edge = put(edge->reference());
232   oop sample_object = edge->pointee();
233   assert(sample_object != NULL, "invariant");
234   assert(sample_object->mark().is_marked(), "invariant");
235   sample_object->set_mark(markWord::from_pointer(leak_context_edge));
236   return leak_context_edge;
237 }
238 
239 /*
240  * The purpose of put_chain() is to reify the edge sequence
241  * discovered during heap traversal with a normalized logical copy.
242  * This copy consist of two sub-sequences and a connecting link (skip edge).
243  *
244  * "current" can be thought of as the cursor (search) edge, it is not in the edge store.
245  * "previous" is always an edge in the edge store.
246  * The leak context edge is the edge adjacent to the leak candidate object, always an edge in the edge store.
247  */
248 void EdgeStore::put_chain(const Edge* chain, size_t length) {
249   assert(chain != NULL, "invariant");
250   assert(chain->distance_to_root() + 1 == length, "invariant");
251   StoredEdge* const leak_context_edge = associate_leak_context_with_candidate(chain);
252   assert(leak_context_edge != NULL, "invariant");
253   assert(leak_context_edge->parent() == NULL, "invariant");
254 
255   if (1 == length) {

  1 /*
  2  * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  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
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #include "precompiled.hpp"
 26 #include "jfr/leakprofiler/chains/edgeStore.hpp"
 27 #include "jfr/leakprofiler/chains/edgeUtils.hpp"
 28 #include "jfr/leakprofiler/sampling/objectSample.hpp"
 29 #include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
 30 #include "oops/oop.inline.hpp"
 31 #include "runtime/safepoint.hpp"
 32 
 33 StoredEdge::StoredEdge(const Edge* parent, UnifiedOopRef reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
 34 
 35 StoredEdge::StoredEdge(const Edge& edge) : Edge(edge), _gc_root_id(0), _skip_length(0) {}
 36 
 37 StoredEdge::StoredEdge(const StoredEdge& edge) : Edge(edge), _gc_root_id(edge._gc_root_id), _skip_length(edge._skip_length) {}
 38 
 39 traceid EdgeStore::_edge_id_counter = 0;
 40 









 41 bool EdgeStore::is_empty() const {
 42   return !_edges->has_entries();
 43 }
 44 
 45 void EdgeStore::on_link(EdgeEntry* entry) {
 46   assert(entry != NULL, "invariant");
 47   assert(entry->id() == 0, "invariant");
 48   entry->set_id(++_edge_id_counter);
 49 }
 50 
 51 bool EdgeStore::on_equals(uintptr_t hash, const EdgeEntry* entry) {
 52   assert(entry != NULL, "invariant");
 53   assert(entry->hash() == hash, "invariant");
 54   return true;
 55 }
 56 
 57 void EdgeStore::on_unlink(EdgeEntry* entry) {
 58   assert(entry != NULL, "invariant");
 59   // nothing
 60 }

200 
201 bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t limit) {
202   assert(*previous != NULL, "invariant");
203   assert(*current != NULL, "invariant");
204   size_t depth = 1;
205   while (*current != NULL && depth < limit) {
206     StoredEdge* stored_edge = get((*current)->reference());
207     if (stored_edge != NULL) {
208       link_with_existing_chain(stored_edge, previous, depth);
209       return true;
210     }
211     stored_edge = link_new_edge(previous, current);
212     assert((*previous)->parent() != NULL, "invariant");
213     *previous = stored_edge;
214     *current = (*current)->parent();
215     ++depth;
216   }
217   return NULL == *current;
218 }
219 
220 static GrowableArray<const StoredEdge*>* _leak_context_edges = nullptr;
221 
222 EdgeStore::EdgeStore() : _edges(new EdgeHashTable(this)) {}
223 
224 EdgeStore::~EdgeStore() {
225   assert(_edges != NULL, "invariant");
226   delete _edges;
227   delete _leak_context_edges;
228   _leak_context_edges = nullptr;
229 }
230 
231 static int leak_context_edge_idx(const ObjectSample* sample) {
232   assert(sample != nullptr, "invariant");
233   return static_cast<int>(sample->object()->mark().value()) >> markWord::lock_bits;
234 }
235 
236 bool EdgeStore::has_leak_context(const ObjectSample* sample) const {
237   const int idx = leak_context_edge_idx(sample);
238   if (idx == 0) {
239     return false;
240   }
241   assert(idx > 0, "invariant");
242   assert(_leak_context_edges != nullptr, "invariant");
243   assert(idx < _leak_context_edges->length(), "invariant");
244   assert(_leak_context_edges->at(idx) != nullptr, "invariant");
245   return true;
246 }
247 
248 const StoredEdge* EdgeStore::get(const ObjectSample* sample) const {
249   assert(sample != nullptr, "invariant");
250   if (_leak_context_edges != nullptr) {
251     assert(SafepointSynchronize::is_at_safepoint(), "invariant");
252     const int idx = leak_context_edge_idx(sample);
253     if (idx > 0) {
254       assert(idx < _leak_context_edges->length(), "invariant");
255       const StoredEdge* const edge =_leak_context_edges->at(idx);
256       assert(edge != nullptr, "invariant");
257       return edge;
258     }
259   }
260   return get(UnifiedOopRef::encode_in_native(sample->object_addr()));
261 }
262 
263 #ifdef ASSERT
264 // max_idx to ensure idx fit in lower 32-bits of markword together with lock bits.
265 static constexpr const int max_idx =  right_n_bits(32 - markWord::lock_bits);
266 
267 static void store_idx_precondition(oop sample_object, int idx) {
268   assert(sample_object != NULL, "invariant");
269   assert(sample_object->mark().is_marked(), "invariant");
270   assert(idx > 0, "invariant");
271   assert(idx <= max_idx, "invariant");
272 }
273 #endif
274 
275 static void store_idx_in_markword(oop sample_object, int idx) {
276   DEBUG_ONLY(store_idx_precondition(sample_object, idx);)
277   const markWord idx_mark_word(sample_object->mark().value() | idx << markWord::lock_bits);
278   sample_object->set_mark(idx_mark_word);
279   assert(sample_object->mark().is_marked(), "must still be marked");
280 }
281 
282 static const int initial_size = 64;
283 
284 static int save(const StoredEdge* edge) {
285   assert(edge != nullptr, "invariant");
286   if (_leak_context_edges == nullptr) {
287     _leak_context_edges = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<const StoredEdge*>(initial_size, mtTracing);
288     _leak_context_edges->append(nullptr); // next idx now at 1, for disambiguation in markword.
289   }
290   return _leak_context_edges->append(edge);
291 }
292 
293 // We associate the leak context edge with the leak candidate object by saving the
294 // edge in an array and storing the array idx (shifted) into the markword of the candidate object.
295 static void associate_with_candidate(const StoredEdge* leak_context_edge) {
296   assert(leak_context_edge != nullptr, "invariant");
297   store_idx_in_markword(leak_context_edge->pointee(), save(leak_context_edge));
298 }
299 
300 StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {
301   assert(edge != NULL, "invariant");
302   assert(!contains(edge->reference()), "invariant");
303   StoredEdge* const leak_context_edge = put(edge->reference());
304   associate_with_candidate(leak_context_edge);



305   return leak_context_edge;
306 }
307 
308 /*
309  * The purpose of put_chain() is to reify the edge sequence
310  * discovered during heap traversal with a normalized logical copy.
311  * This copy consist of two sub-sequences and a connecting link (skip edge).
312  *
313  * "current" can be thought of as the cursor (search) edge, it is not in the edge store.
314  * "previous" is always an edge in the edge store.
315  * The leak context edge is the edge adjacent to the leak candidate object, always an edge in the edge store.
316  */
317 void EdgeStore::put_chain(const Edge* chain, size_t length) {
318   assert(chain != NULL, "invariant");
319   assert(chain->distance_to_root() + 1 == length, "invariant");
320   StoredEdge* const leak_context_edge = associate_leak_context_with_candidate(chain);
321   assert(leak_context_edge != NULL, "invariant");
322   assert(leak_context_edge->parent() == NULL, "invariant");
323 
324   if (1 == length) {
< prev index next >