Skip to content

Draft: Test/shen oc #26376

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

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3da9f89
Testing ObjectCount event with Shenandoah collector
pf0n Jul 9, 2025
ec5ad1a
Created ObjectCount event tests for G1Full and ParallelOld
pf0n Jul 9, 2025
354deee
Initiated GC for ObjectCount testing
pf0n Jul 9, 2025
359caff
Removed unnecessary duplicate calls to ObjectCountEventVerifier in Ob…
pf0n Jul 10, 2025
adea2fc
ObjectCount event test with g1 full
pf0n Jul 14, 2025
c535645
Separated ObjectCount and ObjectCountAfterGC
pf0n Jul 15, 2025
a135b2d
Minimize code duplication by adding templates to ObjectCountEvent sender
pf0n Jul 16, 2025
4826229
ObjectCount data will be emitted if ObjectCountAfterGC is sending data
pf0n Jul 16, 2025
00b15d6
Delete src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp
pf0n Jul 16, 2025
461b71c
Delete src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp
pf0n Jul 16, 2025
33aa1da
Delete src/hotspot/share/gc/shared/objectCountEventSender.cpp
pf0n Jul 16, 2025
cb368f6
Delete src/hotspot/share/gc/shared/objectCountEventSender.hpp
pf0n Jul 16, 2025
3d05ece
Added object counting to Shenandoah
pf0n Jul 17, 2025
523ec03
Merge branch 'test/shen-oc' of https://github.com/pf0n/jdk into test/…
pf0n Jul 17, 2025
82bb883
Templates for ObjectCountEventSenderClosure
pf0n Jul 17, 2025
405e0d9
Updated file for objectCountEventSenderTemplate.hpp
pf0n Jul 17, 2025
d1a1e6b
Updated header gaurds for objectCountEventSenderTemplate.hpp
pf0n Jul 17, 2025
a868e9b
Removed whitespace changes
pf0n Jul 18, 2025
16eee14
Attempt to fix assert error
pf0n Jul 18, 2025
e4747f2
Removed iostream in objectCountEventSenderTemplate
pf0n Jul 18, 2025
0a9c094
Add template for the method that reports object count and updated res…
pf0n Jul 18, 2025
b88dce2
Reverting back to old commit
pf0n Jul 21, 2025
5f912be
Uncommented report_object_count_after_gc
pf0n Jul 21, 2025
08fc38c
Added KlassInfoTable to ObjectCount class
pf0n Jul 21, 2025
4c02ed1
Restored objectCountEventSender
pf0n Jul 22, 2025
520f534
Efficient implementation of ObjectCountAfterGC
pf0n Jul 22, 2025
b3b5706
New closure for object counting
pf0n Jul 22, 2025
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
36 changes: 32 additions & 4 deletions src/hotspot/share/gc/shared/gcTrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include "gc/shared/gcId.hpp"
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTrace.hpp"
#include "jfr/jfrEvents.hpp"
#include "gc/shared/objectCountClosure.hpp"
#include "gc/shared/objectCountEventSender.hpp"
#include "gc/shared/referenceProcessorStats.hpp"
#include "memory/heapInspection.hpp"
Expand Down Expand Up @@ -74,6 +76,8 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con
}

#if INCLUDE_SERVICES

template <typename Event>
class ObjectCountEventSenderClosure : public KlassInfoClosure {
const double _size_threshold_percentage;
const size_t _total_size_in_words;
Expand All @@ -88,7 +92,8 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure {

virtual void do_cinfo(KlassInfoEntry* entry) {
if (should_send_event(entry)) {
ObjectCountEventSender::send(entry, _timestamp);
ObjectCountEventSender::send<Event>(entry, _timestamp);
// Event::send(entry, _timestamp);
}
}

Expand All @@ -99,21 +104,39 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure {
}
};

void GCTracer::report_object_count(KlassInfoTable* cit) {
ObjectCountEventSenderClosure<EventObjectCountAfterGC> event_sender(cit->size_of_instances_in_words(), Ticks::now());
cit->iterate(&event_sender);
ObjectCountClosure::reset_table();
// if (Event::should_send_event()) {
// ResourceMark rm;

// KlassInfoTable cit(false);
// if (!cit.allocation_failed()) {
// HeapInspection hi;
// hi.populate_table(&cit, is_alive_cl, workers);
// ObjectCountEventSenderClosure<Event> event_sender(cit.size_of_instances_in_words(), Ticks::now());
// cit.iterate(&event_sender);
// }
// }
}

void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the only difference between these two methods is the event-sender type passed in the closure. You could make this a template method and pass the event-sender type as a parameter to the template method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, you want to not do the class info table gathering here all at one point, but as you mark objects. Then once the marking is completed, you would send the events by iterating over the table after marking is completed, but you want to do that outside of a safepoint (after the remark, for the case of Shenandoah).

Copy link

@pf0n pf0n Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove the other report_object_count method. I just kept it there for right now just to test the functionality of ObjectCount in Shenandoah. I'll change the report_object_count_after_gc method (might rename it, since it sounds misleading when the ObjectCount event calls this method) to be a template method.

you want to not do the class info table gathering here all at one point, but as you mark objects

I'll create a closure that does the class info table as I mark objects like discussed in yesterday's meeting.

you want to do that outside of a safepoint

I'll make sure to send events concurrently with the application.

assert(is_alive_cl != nullptr, "Must supply function to check liveness");

if (ObjectCountEventSender::should_send_event()) {
if (ObjectCountEventSender::should_send_event<EventObjectCountAfterGC>()) {
ResourceMark rm;

KlassInfoTable cit(false);
if (!cit.allocation_failed()) {
HeapInspection hi;
hi.populate_table(&cit, is_alive_cl, workers);
ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now());
// ObjectCountEventSenderClosure<ObjectCountAfterGCEventSender> event_sender(cit.size_of_instances_in_words(), Ticks::now());
ObjectCountEventSenderClosure<EventObjectCountAfterGC> event_sender(cit.size_of_instances_in_words(), Ticks::now());
cit.iterate(&event_sender);
}
}
}

#endif // INCLUDE_SERVICES

void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const {
Expand Down Expand Up @@ -187,3 +210,8 @@ void ParallelOldTracer::report_dense_prefix(void* dense_prefix) {
void OldGCTracer::report_concurrent_mode_failure() {
send_concurrent_mode_failure_event();
}

// #if INCLUDE_SERVICES
// template void GCTracer::report_object_count<ObjectCountEventSender>(KlassInfoTable*);
// template void GCTracer::report_object_count<ObjectCountAfterGCEventSender>(KlassInfoTable*);
// #endif // INCLUDE_SERVICES
6 changes: 5 additions & 1 deletion src/hotspot/share/gc/shared/gcTrace.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "memory/referenceType.hpp"
#include "utilities/macros.hpp"
#include "utilities/ticks.hpp"
#include "memory/heapInspection.hpp"

class GCHeapSummary;
class MetaspaceChunkFreeListSummary;
Expand Down Expand Up @@ -103,7 +104,10 @@ class GCTracer {
void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const;
void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const;
void report_gc_reference_stats(const ReferenceProcessorStats& rp) const;
void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN;

void report_object_count(KlassInfoTable* cit) NOT_SERVICES_RETURN;

void report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) NOT_SERVICES_RETURN;
void report_cpu_time_event(double user_time, double system_time, double real_time) const;

protected:
Expand Down
35 changes: 35 additions & 0 deletions src/hotspot/share/gc/shared/objectCountClosure.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "gc/shared/gcId.hpp"
#include "gc/shared/objectCountClosure.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/heapInspection.hpp"
#include "utilities/macros.hpp"
#include "utilities/ticks.hpp"

class KlassInfoEntry;
class Klass;

KlassInfoTable ObjectCountClosure::cit(false);

void ObjectCountClosure::reset_table() {
if (!check_table_exists()) {
return;
}
cit.~KlassInfoTable();
::new((void*)&cit) KlassInfoTable(false);
}

bool ObjectCountClosure::check_table_exists() {
return !cit.allocation_failed();
}

bool ObjectCountClosure::record_object(oop o) {
if (!check_table_exists()) {
return false;
}
cit.record_instance(o);
return true;
}

KlassInfoTable* ObjectCountClosure::get_table() {
return check_table_exists() ? &cit : nullptr;
}
24 changes: 24 additions & 0 deletions src/hotspot/share/gc/shared/objectCountClosure.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP
#define SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP

#include "gc/shared/gcId.hpp"
#include "gc/shared/objectCountEventSender.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/heapInspection.hpp"
#include "utilities/macros.hpp"
#include "utilities/ticks.hpp"

class KlassInfoEntry;
class Klass;

class ObjectCountClosure : public ObjectCountEventSender {
static KlassInfoTable cit;

public:
static bool check_table_exists();
static bool record_object(oop o);
static KlassInfoTable* get_table();
static void reset_table();
};

#endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP
19 changes: 16 additions & 3 deletions src/hotspot/share/gc/shared/objectCountEventSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@
#include "utilities/ticks.hpp"
#if INCLUDE_SERVICES

template <class Event>
bool ObjectCountEventSender::should_send_event() {
#if INCLUDE_JFR
return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled();
return _should_send_requestable_event || Event::is_enabled();
#else
return false;
#endif // INCLUDE_JFR
Expand Down Expand Up @@ -63,13 +64,25 @@ void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, ju
}
}


template <class Event>
void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
Klass* klass = entry->klass();
jlong count = entry->count();
julong total_size = entry->words() * BytesPerWord;

send_event_if_enabled<EventObjectCount>(klass, count, total_size, timestamp);
send_event_if_enabled<EventObjectCountAfterGC>(klass, count, total_size, timestamp);
send_event_if_enabled<Event>(klass, count, total_size, timestamp);
// If sending ObjectCountAfterGCEvent, check if ObjectCount is enabled and send event data to ObjectCount
// If sending ObjectCountEvent, do not send send ObjectCountAfterGCEvent
if (std::is_same<Event, EventObjectCountAfterGC>::value && ObjectCountEventSender::should_send_event<EventObjectCount>()) {
send_event_if_enabled<EventObjectCount>(klass, count, total_size, timestamp);
}
}

template bool ObjectCountEventSender::should_send_event<EventObjectCount>();
template bool ObjectCountEventSender::should_send_event<EventObjectCountAfterGC>();

template void ObjectCountEventSender::send<EventObjectCount>(const KlassInfoEntry*, const Ticks&);
template void ObjectCountEventSender::send<EventObjectCountAfterGC>(const KlassInfoEntry*, const Ticks&);

#endif // INCLUDE_SERVICES
6 changes: 5 additions & 1 deletion src/hotspot/share/gc/shared/objectCountEventSender.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,21 @@ class Klass;
class ObjectCountEventSender : public AllStatic {
static bool _should_send_requestable_event;

template <typename T>
template <typename Event>
static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp);

public:
static void enable_requestable_event();
static void disable_requestable_event();

template <class Event>
static void send(const KlassInfoEntry* entry, const Ticks& timestamp);

template <class Event>
static bool should_send_event();
};


#endif // INCLUDE_SERVICES

#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP
122 changes: 122 additions & 0 deletions src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP
// #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP

// #include "gc/shared/gcId.hpp"
// #include "jfr/jfrEvents.hpp"
// #include "memory/heapInspection.hpp"
// #include "utilities/macros.hpp"
// #include "utilities/ticks.hpp"
// #if INCLUDE_SERVICES

// class KlassInfoEntry;
// class Klass;

// template <typename Event>
// class ObjectCountEventSenderTemplate : public AllStatic {
// static bool _should_send_requestable_event;
// static KlassInfoTable cit;

// template <typename T>
// static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp);

// public:
// static bool check_table_exists();
// static KlassInfoTable* get_table();
// static void reset_table();


Check failure on line 27 in src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp

View check run for this annotation

openjdk / jcheck-openjdk/jdk-26376

Whitespace error

Column 0: trailing whitespace Column 1: trailing whitespace

Check failure on line 27 in src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp

View check run for this annotation

openjdk / jcheck-openjdk/jdk-26433

Whitespace error

Column 0: trailing whitespace Column 1: trailing whitespace
// static void enable_requestable_event();
// static void disable_requestable_event();
// static bool record_object_instance(oop o);

// static void send(const KlassInfoEntry* entry, const Ticks& timestamp);
// static bool should_send_event();
// };

// typedef ObjectCountEventSenderTemplate<EventObjectCount> ObjectCountEventSender;
// typedef ObjectCountEventSenderTemplate<EventObjectCountAfterGC> ObjectCountAfterGCEventSender;

// template <typename Event>
// bool ObjectCountEventSenderTemplate<Event>::should_send_event() {
// #if INCLUDE_JFR
// return _should_send_requestable_event || Event::is_enabled();
// #else
// return false;
// #endif // INCLUDE_JFR
// }

// template <typename Event>
// bool ObjectCountEventSenderTemplate<Event>::_should_send_requestable_event = false;

// template <typename Event>
// KlassInfoTable ObjectCountEventSenderTemplate<Event>::cit(false);

// template <typename Event>
// void ObjectCountEventSenderTemplate<Event>::reset_table() {
// cit.~KlassInfoTable();
// ::new((void*)&cit) KlassInfoTable(false);
// }


// template <typename Event>
// bool ObjectCountEventSenderTemplate<Event>::check_table_exists() {
// return !cit.allocation_failed();
// }

// template <typename Event>
// bool ObjectCountEventSenderTemplate<Event>::record_object_instance(oop o) {
// if (!check_table_exists()) {
// return false;

Check failure on line 69 in src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp

View check run for this annotation

openjdk / jcheck-openjdk/jdk-26376

Whitespace error

Column 20: trailing whitespace

Check failure on line 69 in src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp

View check run for this annotation

openjdk / jcheck-openjdk/jdk-26433

Whitespace error

Column 20: trailing whitespace
// }
// cit.record_instance(o);
// return true;
// }

// template <typename Event>
// KlassInfoTable* ObjectCountEventSenderTemplate<Event>::get_table() {
// return &cit;
// }


// template <typename Event>
// void ObjectCountEventSenderTemplate<Event>::enable_requestable_event() {
// _should_send_requestable_event = true;
// }


// template <typename Event>
// void ObjectCountEventSenderTemplate<Event>::disable_requestable_event() {
// _should_send_requestable_event = false;
// }

// template <typename Event>
// template <typename T>
// void ObjectCountEventSenderTemplate<Event>::send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp) {
// T event(UNTIMED);
// if (event.should_commit()) {
// event.set_starttime(timestamp);
// event.set_endtime(timestamp);
// event.set_gcId(GCId::current());
// event.set_objectClass(klass);
// event.set_count(count);
// event.set_totalSize(size);
// event.commit();
// }
// }

// template <typename Event>
// void ObjectCountEventSenderTemplate<Event>::send(const KlassInfoEntry* entry, const Ticks& timestamp) {
// Klass* klass = entry->klass();
// jlong count = entry->count();
// julong total_size = entry->words() * BytesPerWord;

// send_event_if_enabled<Event>(klass, count, total_size, timestamp);
// // If sending ObjectCountAfterGCEvent, check if ObjectCount is enabled and send event data to ObjectCount
// // If sending ObjectCountEvent, do not send send ObjectCountAfterGCEvent
// if (std::is_same<Event, EventObjectCountAfterGC>::value && ObjectCountEventSender::should_send_event()) {
// send_event_if_enabled<EventObjectCount>(klass, count, total_size, timestamp);
// }
// }
// #endif // INCLUDE_SERVICES

// #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP
17 changes: 17 additions & 0 deletions src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/collectorCounters.hpp"
#include "gc/shared/continuationGCSupport.inline.hpp"
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/objectCountEventSender.hpp"
#include "gc/shared/objectCountClosure.hpp"
#include "gc/shenandoah/shenandoahBreakpoint.hpp"
#include "gc/shenandoah/shenandoahClosures.inline.hpp"
#include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
#include "gc/shenandoah/shenandoahConcurrentGC.hpp"
#include "gc/shenandoah/shenandoahFreeSet.hpp"
#include "gc/shenandoah/shenandoahGeneration.hpp"
#include "gc/shenandoah/shenandoahGenerationalHeap.hpp"
#include "gc/shenandoah/shenandoahHeap.hpp"
#include "gc/shenandoah/shenandoahLock.hpp"
#include "gc/shenandoah/shenandoahMark.inline.hpp"
#include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
Expand Down Expand Up @@ -770,6 +774,19 @@ void ShenandoahConcurrentGC::op_final_mark() {
heap->verifier()->verify_roots_no_forwarded();
}

// Efficient implementation:
{
KlassInfoTable* cit = ObjectCountClosure::get_table();
heap->tracer()->report_object_count(cit);
}

// Naive implementation:
// {
// ShenandoahIsAliveClosure is_alive;
// heap->tracer()->report_object_count_after_gc(&is_alive, heap->workers());
// }


if (!heap->cancelled_gc()) {
_mark.finish_mark();
assert(!heap->cancelled_gc(), "STW mark cannot OOM");
Expand Down
Loading