Skip to content

Commit

Permalink
[Backport] 8275415: Prepare Leak Profiler for Lilliput
Browse files Browse the repository at this point in the history
Summary: Prepare Leak Profiler for Lilliput

Test Plan: CICD

Reviewed-by: ddh, yanglong

Issue: #704
  • Loading branch information
mmyxym committed Nov 1, 2023
1 parent 7744075 commit 65677bf
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 16 deletions.
86 changes: 72 additions & 14 deletions src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
#include "precompiled.hpp"
#include "jfr/leakprofiler/chains/edgeStore.hpp"
#include "jfr/leakprofiler/chains/edgeUtils.hpp"
#include "jfr/leakprofiler/sampling/objectSample.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/safepoint.hpp"

StoredEdge::StoredEdge() : Edge() {}
StoredEdge::StoredEdge(const Edge* parent, const oop* reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
Expand All @@ -42,15 +44,6 @@ void StoredEdge::operator=(const StoredEdge& edge) {

traceid EdgeStore::_edge_id_counter = 0;

EdgeStore::EdgeStore() : _edges(NULL) {
_edges = new EdgeHashTable(this);
}

EdgeStore::~EdgeStore() {
assert(_edges != NULL, "invariant");
delete _edges;
}

bool EdgeStore::is_empty() const {
return !_edges->has_entries();
}
Expand Down Expand Up @@ -230,15 +223,80 @@ bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t li
return NULL == *current;
}

// Install the immediate edge into the mark word of the leak candidate object
static GrowableArray<const StoredEdge*>* _leak_context_edges = NULL;

EdgeStore::EdgeStore() : _edges(new EdgeHashTable(this)) {}

EdgeStore::~EdgeStore() {
assert(_edges != NULL, "invariant");
delete _edges;
delete _leak_context_edges;
_leak_context_edges = NULL;
}

static int leak_context_edge_idx(const ObjectSample* sample) {
assert(sample != NULL, "invariant");
return static_cast<int>(sample->object()->mark()->value()) >> markOopDesc::lock_bits;
}

bool EdgeStore::has_leak_context(const ObjectSample* sample) const {
return leak_context_edge_idx(sample) != 0;
}

const StoredEdge* EdgeStore::get(const ObjectSample* sample) const {
assert(sample != NULL, "invariant");
if (_leak_context_edges != NULL) {
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
const int idx = leak_context_edge_idx(sample);
if (idx > 0) {
return _leak_context_edges->at(idx);
}
}
return get(sample->object_addr());
}

#ifdef ASSERT
// max_idx to ensure idx fit in lower 32-bits of markword together with lock bits.
static const int max_idx = right_n_bits(32 - markOopDesc::lock_bits);

static void store_idx_precondition(oop sample_object, int idx) {
assert(sample_object != NULL, "invariant");
assert(sample_object->mark()->is_marked(), "invariant");
assert(idx > 0, "invariant");
assert(idx <= max_idx, "invariant");
}
#endif

static void store_idx_in_markword(oop sample_object, int idx) {
DEBUG_ONLY(store_idx_precondition(sample_object, idx);)
const markOop idx_mark_word = markOop(sample_object->mark()->value() | idx << markOopDesc::lock_bits);
sample_object->set_mark(idx_mark_word);
assert(sample_object->mark()->is_marked(), "must still be marked");
}

static const int initial_size = 64;

static int save(const StoredEdge* edge) {
assert(edge != NULL, "invariant");
if (_leak_context_edges == NULL) {
_leak_context_edges = new (ResourceObj::C_HEAP, mtTracing)GrowableArray<const StoredEdge*>(initial_size, mtTracing);
_leak_context_edges->append(NULL); // next idx now at 1, for disambiguation in markword.
}
return _leak_context_edges->append(edge);
}

// We associate the leak context edge with the leak candidate object by saving the
// edge in an array and storing the array idx (shifted) into the markword of the candidate object.
static void associate_with_candidate(const StoredEdge* leak_context_edge) {
assert(leak_context_edge != NULL, "invariant");
store_idx_in_markword(leak_context_edge->pointee(), save(leak_context_edge));
}

StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {
assert(edge != NULL, "invariant");
assert(!contains(edge->reference()), "invariant");
StoredEdge* const leak_context_edge = put(edge->reference());
oop sample_object = edge->pointee();
assert(sample_object != NULL, "invariant");
assert(sample_object->mark()->is_marked(), "invariant");
sample_object->set_mark(markOop(leak_context_edge));
associate_with_candidate(leak_context_edge);
return leak_context_edge;
}

Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "memory/allocation.hpp"

typedef u8 traceid;
class ObjectSample;

class StoredEdge : public Edge {
private:
Expand Down Expand Up @@ -79,6 +80,7 @@ class EdgeStore : public CHeapObj<mtTracing> {
void on_unlink(EdgeEntry* entry);

StoredEdge* get(const oop* reference) const;
const StoredEdge* get(const ObjectSample* sample) const;
StoredEdge* put(const oop* reference);
traceid gc_root_id(const Edge* edge) const;

Expand All @@ -90,6 +92,7 @@ class EdgeStore : public CHeapObj<mtTracing> {
void store_gc_root_id_in_leak_context_edge(StoredEdge* leak_context_edge, const Edge* root) const;
StoredEdge* link_new_edge(StoredEdge** previous, const Edge** current);
void link_with_existing_chain(const StoredEdge* current_stored, StoredEdge** previous, size_t previous_length);
bool has_leak_context(const ObjectSample* sample) const;

template <typename T>
void iterate(T& functor) const { _edges->iterate_value<T>(functor); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ void EventEmitter::write_event(const ObjectSample* sample, EdgeStore* edge_store
traceid gc_root_id = 0;
const Edge* edge = NULL;
if (SafepointSynchronize::is_at_safepoint()) {
if (!(*object_addr)->mark()->is_marked()) {
edge = (const Edge*)(*object_addr)->mark();
if (edge_store->has_leak_context(sample)) {
edge = edge_store->get(sample);
}
}
if (edge == NULL) {
Expand All @@ -125,6 +125,7 @@ void EventEmitter::write_event(const ObjectSample* sample, EdgeStore* edge_store
}

assert(edge != NULL, "invariant");
assert(edge->pointee() == sample->object(), "invariant");
const traceid object_id = edge_store->get_id(edge);
assert(object_id != 0, "invariant");

Expand Down

0 comments on commit 65677bf

Please sign in to comment.