Skip to content

Commit f25f701

Browse files
author
Markus Grönlund
committed
8353226: JFR: emit old object samples must be transitive closure complete for segment
Reviewed-by: egahlin
1 parent aff5aa7 commit f25f701

File tree

5 files changed

+61
-4
lines changed

5 files changed

+61
-4
lines changed

src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ void StackTraceBlobInstaller::install(ObjectSample* sample) {
256256
writer.write_type(TYPE_STACKTRACE);
257257
writer.write_count(1);
258258
ObjectSampleCheckpoint::write_stacktrace(stack_trace, writer);
259-
blob = writer.copy();
259+
blob = stack_trace->should_write() ? writer.copy() : writer.move();
260260
_cache.put(sample, blob);
261261
sample->set_stacktrace(blob);
262262
}
@@ -362,9 +362,17 @@ static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& w
362362
}
363363
}
364364

365+
static GrowableArray<traceid>* _stacktrace_ids = nullptr;
366+
365367
static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer) {
368+
assert(_stacktrace_ids != nullptr, "invariant");
366369
if (sample->has_stacktrace()) {
367370
write_blob(sample->stacktrace(), writer);
371+
return;
372+
}
373+
const traceid stacktrace_id = sample->stack_trace_id();
374+
if (stacktrace_id != 0) {
375+
_stacktrace_ids->append(stacktrace_id);
368376
}
369377
}
370378

@@ -402,7 +410,15 @@ void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge
402410
assert(sampler != nullptr, "invariant");
403411
assert(edge_store != nullptr, "invariant");
404412
assert(thread != nullptr, "invariant");
405-
write_sample_blobs(sampler, emit_all, thread);
413+
{
414+
ResourceMark rm(thread);
415+
_stacktrace_ids = new GrowableArray<traceid>(JfrOptionSet::old_object_queue_size());
416+
write_sample_blobs(sampler, emit_all, thread);
417+
if (_stacktrace_ids->is_nonempty()) {
418+
_stacktrace_ids->sort(sort_traceid);
419+
JfrStackTraceRepository::write_leak_profiler(_stacktrace_ids, thread);
420+
}
421+
}
406422
// write reference chains
407423
if (!edge_store->is_empty()) {
408424
JfrCheckpointWriter writer(thread);

src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ void JfrStackTrace::write(JfrChunkWriter& sw) const {
102102
}
103103

104104
void JfrStackTrace::write(JfrCheckpointWriter& cpw) const {
105+
assert(!_written, "invariant");
105106
write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
107+
_written = true;
106108
}
107109

108110
bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {

src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ class JfrStackTrace : public JfrCHeapObj {
8282

8383
const JfrStackTrace* next() const { return _next; }
8484

85-
bool should_write() const { return !_written; }
8685
void write(JfrChunkWriter& cw) const;
8786
void write(JfrCheckpointWriter& cpw) const;
8887
bool equals(const JfrStackTrace& rhs) const;
@@ -107,6 +106,7 @@ class JfrStackTrace : public JfrCHeapObj {
107106
public:
108107
traceid hash() const { return _hash; }
109108
traceid id() const { return _id; }
109+
bool should_write() const { return !_written; }
110110
};
111111

112112
#endif // SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACE_HPP

src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
2828
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
2929
#include "jfr/support/jfrThreadLocal.hpp"
30+
#include "jfr/utilities/jfrPredicate.hpp"
31+
#include "jfr/utilities/jfrRelation.hpp"
3032
#include "runtime/mutexLocker.hpp"
33+
#include "utilities/growableArray.hpp"
3134

3235
/*
3336
* There are two separate repository instances.
@@ -242,3 +245,36 @@ traceid JfrStackTraceRepository::next_id() {
242245
MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
243246
return ++_next_id;
244247
}
248+
249+
static inline bool should_write(const JfrStackTrace* stacktrace, GrowableArray<traceid>* leakp_set) {
250+
assert(stacktrace != nullptr, "invariant");
251+
return stacktrace->should_write() && JfrPredicate<traceid, compare_traceid>::test(leakp_set, stacktrace->id());
252+
}
253+
254+
void JfrStackTraceRepository::write_leak_profiler(GrowableArray<traceid>* leakp_set, Thread* t) {
255+
assert(leakp_set != nullptr, "invariant");
256+
assert(leakp_set->is_nonempty(), "invariant");
257+
assert(t != nullptr, "invariant");
258+
259+
JfrCheckpointWriter writer(t);
260+
writer.write_type(TYPE_STACKTRACE);
261+
const int64_t count_offset = writer.reserve(sizeof(u4)); // Don't know how many yet
262+
263+
int count = 0;
264+
const JfrStackTraceRepository& repo = leak_profiler_instance();
265+
266+
for (u4 i = 0; i < TABLE_SIZE; ++i) {
267+
const JfrStackTrace* stacktrace = repo._table[i];
268+
while (stacktrace != nullptr) {
269+
if (should_write(stacktrace, leakp_set)) {
270+
stacktrace->write(writer);
271+
++count;
272+
}
273+
stacktrace = stacktrace->next();
274+
}
275+
}
276+
277+
assert(count > 0, "invariant");
278+
assert(count <= leakp_set->length(), "invariant");
279+
writer.write_count(count, count_offset);
280+
}

src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,11 @@
3030
#include "jfr/utilities/jfrTypes.hpp"
3131

3232
class JavaThread;
33-
class JfrCheckpointWriter;
3433
class JfrChunkWriter;
3534

35+
template <typename>
36+
class GrowableArray;
37+
3638
class JfrStackTraceRepository : public JfrCHeapObj {
3739
friend class JfrDeprecatedEdge;
3840
friend class JfrRecorder;
@@ -62,6 +64,7 @@ class JfrStackTraceRepository : public JfrCHeapObj {
6264

6365
static const JfrStackTrace* lookup_for_leak_profiler(traceid hash, traceid id);
6466
static void record_for_leak_profiler(JavaThread* thread, int skip = 0);
67+
static void write_leak_profiler(GrowableArray<traceid>* leakp_set, Thread* t);
6568
static void clear_leak_profiler();
6669

6770
static traceid next_id();

0 commit comments

Comments
 (0)