Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport] 8275415: Prepare Leak Profiler for Lilliput #706

Merged
merged 1 commit into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading