From 947a244c6d120d68f5336a1759b267165c2c27e3 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 14 Aug 2025 00:30:38 +0000 Subject: [PATCH 1/9] Independent object counting from GC --- src/hotspot/share/gc/shared/gcCause.cpp | 3 ++ src/hotspot/share/gc/shared/gcCause.hpp | 1 + src/hotspot/share/gc/shared/gcTrace.hpp | 4 +-- .../share/gc/shared/gcTrace.inline.hpp | 9 +++--- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- .../gc/shenandoah/shenandoahConcurrentGC.hpp | 2 +- .../shenandoah/shenandoahConcurrentMark.cpp | 3 +- .../gc/shenandoah/shenandoahControlThread.cpp | 31 +++++++++++++++++-- .../gc/shenandoah/shenandoahControlThread.hpp | 1 + .../share/gc/shenandoah/shenandoahMark.cpp | 3 +- .../gc/shenandoah/shenandoahObjectCountGC.cpp | 23 ++++++++++++++ .../gc/shenandoah/shenandoahObjectCountGC.hpp | 17 ++++++++++ .../share/gc/shenandoah/shenandoahSTWMark.cpp | 3 +- .../gc/shenandoah/shenandoah_globals.hpp | 5 +++ .../gc/objectcount/ObjectCountEvent.java | 8 +++-- .../TestObjectCountEventWithShenandoah.java | 2 +- 16 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp diff --git a/src/hotspot/share/gc/shared/gcCause.cpp b/src/hotspot/share/gc/shared/gcCause.cpp index 489a5d32a9033..e18262c00cb6a 100644 --- a/src/hotspot/share/gc/shared/gcCause.cpp +++ b/src/hotspot/share/gc/shared/gcCause.cpp @@ -95,6 +95,9 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _shenandoah_allocation_failure_evac: return "Allocation Failure During Evacuation"; + case _shenandoah_object_count: + return "Object Count Event Enabled"; + case _shenandoah_humongous_allocation_failure: return "Humongous Allocation Failure"; diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index f775d41340dbf..2a3923cad5e30 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -76,6 +76,7 @@ class GCCause : public AllStatic { _shenandoah_humongous_allocation_failure, _shenandoah_concurrent_gc, _shenandoah_upgrade_to_full_gc, + _shenandoah_object_count, _z_timer, _z_warmup, diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 115b618795597..c087b891cc5bc 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -105,8 +105,8 @@ class GCTracer { void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; // Sends event data to the ObjectCount and/or ObjectCountAfterGC event - template - void report_object_count(T* heap) NOT_SERVICES_RETURN; + template + void report_object_count() NOT_SERVICES_RETURN; void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; void report_cpu_time_event(double user_time, double system_time, double real_time) const; diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index b243c4f068bab..dc84fc026b459 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -38,16 +38,17 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -template -void GCTracer::report_object_count(T* heap) { - if (!ObjectCountEventSender::should_send_event()) { +template +void GCTracer::report_object_count() { + if (!ObjectCountEventSender::should_send_event()) { return; } + T* heap = T::heap(); KlassInfoTable* cit = heap->get_cit(); if (!cit->allocation_failed()) { - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index dbd917e887358..4c3a9daa25068 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -318,7 +318,7 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { // Do not report object count during a safepoint assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); - heap->tracer()->report_object_count(heap); + heap->tracer()->report_object_count(); } void ShenandoahConcurrentGC::vmop_entry_init_update_refs() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index d81c49363a230..d90e29a49d833 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -57,7 +57,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { public: ShenandoahConcurrentGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap); - bool collect(GCCause::Cause cause) override; + virtual bool collect(GCCause::Cause cause) override; ShenandoahDegenPoint degen_point() const; void entry_concurrent_update_refs_prepare(ShenandoahHeap* heap); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 2623ecba372cc..50f45c82f7b78 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -174,7 +174,8 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { nullptr : _old_queue_set->queue(worker_id); // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event(); + bool object_count_enabled = ObjectCountEventSender::should_send_event() || + ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 27a7ff54f364c..d9eee3f2b908b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -23,6 +23,7 @@ * */ +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -34,10 +35,13 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" +#include "gc/shenandoah/shenandoahObjectCountGC.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "logging/log.hpp" #include "memory/metaspaceStats.hpp" #include "memory/metaspaceUtils.hpp" +#include "iostream" +#include "gc/shared/gcTrace.inline.hpp" ShenandoahControlThread::ShenandoahControlThread() : ShenandoahController(), @@ -48,6 +52,8 @@ ShenandoahControlThread::ShenandoahControlThread() : } void ShenandoahControlThread::run_service() { + jlong service_start_time = os::javaTimeMillis(); + ShenandoahHeap* const heap = ShenandoahHeap::heap(); const GCMode default_mode = concurrent_normal; const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc; @@ -63,6 +69,8 @@ void ShenandoahControlThread::run_service() { heap->set_cit(&cit); while (!should_terminate()) { + jlong elapsed_time = os::javaTimeMillis() - service_start_time; + const GCCause::Cause cancelled_cause = heap->cancelled_cause(); if (cancelled_cause == GCCause::_shenandoah_stop_vm) { break; @@ -128,7 +136,7 @@ void ShenandoahControlThread::run_service() { const bool gc_requested = (mode != none); assert (!gc_requested || cause != GCCause::_last_gc_cause, "GC cause should be set"); - + if (gc_requested) { // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(heap); @@ -229,6 +237,12 @@ void ShenandoahControlThread::run_service() { // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); + } else { + if (ObjectCountEventSender::should_send_event() && (ShenandoahObjectCountInterval - elapsed_time) <= 0) { + const GCCause::Cause count_clause = GCCause::_shenandoah_object_count; + service_object_count_cycle(count_clause); + service_start_time = os::javaTimeMillis(); + } } // Check if we have seen a new target for soft max heap size or if a gc was requested. @@ -253,7 +267,6 @@ void ShenandoahControlThread::run_service() { } os::naked_short_sleep(sleep); } - heap->set_cit(nullptr); } @@ -362,6 +375,20 @@ void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause gc.collect(cause); } +void ShenandoahControlThread::service_object_count_cycle(GCCause::Cause cause) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + + ShenandoahGCSession session(cause, heap->global_generation()); + + // TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); + + ShenandoahObjectCountGC gc(heap->global_generation()); + gc.collect(cause); + + heap->tracer()->report_object_count(); +} + + void ShenandoahControlThread::request_gc(GCCause::Cause cause) { if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) { handle_requested_gc(cause); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index 9d95b5df7ed30..7c65fdaccb71b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -61,6 +61,7 @@ class ShenandoahControlThread: public ShenandoahController { void service_concurrent_normal_cycle(GCCause::Cause cause); void service_stw_full_cycle(GCCause::Cause cause); void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point); + void service_object_count_cycle(GCCause::Cause cause); void notify_gc_waiters(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 3b8dcc43d3759..fbbc26c83d51e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -70,7 +70,8 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe mark_loop_work(&cl, ld, w, t, req); } else { // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event(); + bool object_count_enabled = ObjectCountEventSender::should_send_event() || + ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp new file mode 100644 index 0000000000000..294552446fd79 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp @@ -0,0 +1,23 @@ +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahObjectCountGC.hpp" + +bool ShenandoahObjectCountGC::collect(GCCause::Cause cause) { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + + entry_reset(); + vmop_entry_init_mark(); + + // TASKQUEUE_STATS_ONLY(_mark.task_queues()->reset_taskqueue_stats()); + + entry_scan_remembered_set(); + entry_mark_roots(); + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_roots)) { + return false; + } + + entry_mark(); + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { + return false; + } + return true; +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp new file mode 100644 index 0000000000000..c927268599558 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp @@ -0,0 +1,17 @@ +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP + +#include "gc/shared/gcCause.hpp" +#include "gc/shenandoah/shenandoahConcurrentGC.hpp" +#include "gc/shenandoah/shenandoahConcurrentMark.hpp" +#include "gc/shenandoah/shenandoahGC.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" + +class ShenandoahObjectCountGC : public ShenandoahConcurrentGC { + public: + ShenandoahObjectCountGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap = false) + : ShenandoahConcurrentGC(generation, do_old_gc_bootstrap) {} + bool collect(GCCause::Cause cause) override; +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 613e2f44edb76..3cf10e78eb9f6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -124,7 +124,8 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { switch (_generation->type()) { case NON_GEN: { // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event(); + bool object_count_enabled = ObjectCountEventSender::should_send_event() || + ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index c51f4f164895d..4d6acb379c998 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -530,6 +530,11 @@ "to prevent starvation of the old collector. Setting this to " \ "0 will allow back to back young collections to run during old " \ "collections.") \ + \ + product(uintx, ShenandoahObjectCountInterval, 0, \ + "Duration in milliseconds to run object counting GC cycles. " \ + "0 means disabled.") \ + range(0, max_uintx) \ // end of GC_SHENANDOAH_FLAGS #endif // SHARE_GC_SHENANDOAH_SHENANDOAH_GLOBALS_HPP diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index 30d9e141d8285..e2521e7326cba 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -2,6 +2,7 @@ import java.nio.file.Files; import java.nio.file.Path; +import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -12,6 +13,8 @@ import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; + + public class ObjectCountEvent { private static final String objectCountEventPath = EventNames.ObjectCount; private static final String gcEventPath = EventNames.GarbageCollection; @@ -27,11 +30,12 @@ public static void test(String gcName) throws Exception { recording.start(); Path tempFile = Path.of("temp.jfr"); + // if temp file exists, assertion recording.dump(tempFile); // Forces chunk rotation System.gc(); recording.stop(); - Files.deleteIfExists(tempFile); + // Files.deleteIfExists(tempFile); System.out.println("gcName=" + gcName); List events = Events.fromRecording(recording); @@ -56,7 +60,7 @@ public static void test(String gcName) throws Exception { System.out.println("Found heapSummaryEvent: " + heapSummaryEvent.get()); Events.assertField(heapSummaryEvent.get(), "heapUsed").atLeast(0L).getValue(); - ObjectCountEventVerifier.verify(objCountEvents); + // ObjectCountEventVerifier.verify(objCountEvents); } private static boolean isMySystemGc(RecordedEvent event, String gcName) { diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java index 3191ebb43d3f2..1a057d5251668 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java @@ -8,7 +8,7 @@ * @requires (vm.gc == "Shenandoah" | vm.gc == null) * & vm.opt.ExplicitGCInvokesConcurrent != false * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEventWithShenandoah + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahObjectCountInterval=300 -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEventWithShenandoah */ public class TestObjectCountEventWithShenandoah { public static void main(String[] args) throws Exception { From c849d25e46b8a9b63b5ef893e142c1694564fd5d Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 13 Aug 2025 17:33:52 -0700 Subject: [PATCH 2/9] Update ObjectCountEvent.java --- test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index e2521e7326cba..6f939505bc9e5 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -2,7 +2,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -13,8 +12,6 @@ import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; - - public class ObjectCountEvent { private static final String objectCountEventPath = EventNames.ObjectCount; private static final String gcEventPath = EventNames.GarbageCollection; From fdd6ea37e7d22e4ae074be1d3a24bf40b1857cca Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 14 Aug 2025 17:11:47 +0000 Subject: [PATCH 3/9] Fixed GCId being undefined --- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 6 +++--- test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index d9eee3f2b908b..37ac08dfb9527 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -23,6 +23,7 @@ * */ +#include "gc/shared/gcTrace.inline.hpp" #include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" #include "gc/shenandoah/mode/shenandoahMode.hpp" @@ -40,8 +41,6 @@ #include "logging/log.hpp" #include "memory/metaspaceStats.hpp" #include "memory/metaspaceUtils.hpp" -#include "iostream" -#include "gc/shared/gcTrace.inline.hpp" ShenandoahControlThread::ShenandoahControlThread() : ShenandoahController(), @@ -239,6 +238,7 @@ void ShenandoahControlThread::run_service() { MetaspaceUtils::print_metaspace_change(meta_sizes); } else { if (ObjectCountEventSender::should_send_event() && (ShenandoahObjectCountInterval - elapsed_time) <= 0) { + GCIdMark gc_id_mark; const GCCause::Cause count_clause = GCCause::_shenandoah_object_count; service_object_count_cycle(count_clause); service_start_time = os::javaTimeMillis(); @@ -380,7 +380,7 @@ void ShenandoahControlThread::service_object_count_cycle(GCCause::Cause cause) { ShenandoahGCSession session(cause, heap->global_generation()); - // TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); + TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); ShenandoahObjectCountGC gc(heap->global_generation()); gc.collect(cause); diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index e2521e7326cba..6f939505bc9e5 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -2,7 +2,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -13,8 +12,6 @@ import jdk.test.lib.jfr.EventNames; import jdk.test.lib.jfr.Events; - - public class ObjectCountEvent { private static final String objectCountEventPath = EventNames.ObjectCount; private static final String gcEventPath = EventNames.GarbageCollection; From 606c2e894f42e83a9c4c3af22387998c9b68fa8a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 14 Aug 2025 21:44:59 +0000 Subject: [PATCH 4/9] Ended GC Phase Timing --- .../share/gc/shenandoah/shenandoahControlThread.cpp | 9 +++++++-- .../share/gc/shenandoah/shenandoahObjectCountGC.cpp | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 37ac08dfb9527..d60ddfd5d7039 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -241,6 +241,10 @@ void ShenandoahControlThread::run_service() { GCIdMark gc_id_mark; const GCCause::Cause count_clause = GCCause::_shenandoah_object_count; service_object_count_cycle(count_clause); + + // Reset GC Cycle + heap->phase_timings()->flush_par_workers_to_cycle(); + heap->phase_timings()->flush_cycle_to_global(); service_start_time = os::javaTimeMillis(); } } @@ -383,9 +387,10 @@ void ShenandoahControlThread::service_object_count_cycle(GCCause::Cause cause) { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); ShenandoahObjectCountGC gc(heap->global_generation()); - gc.collect(cause); - heap->tracer()->report_object_count(); + if (gc.collect(cause)) { + heap->tracer()->report_object_count(); + } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp index 294552446fd79..58a036a401db7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp @@ -19,5 +19,7 @@ bool ShenandoahObjectCountGC::collect(GCCause::Cause cause) { if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { return false; } + + entry_reset_after_collect(); return true; } From adb492b392596e544ba0512833afbcdec5284487 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 18 Aug 2025 18:06:54 +0000 Subject: [PATCH 5/9] Renamed gcCause, added proper documentation to shenandoahJFRObjectCountGC, and redefined final mark --- src/hotspot/share/gc/shared/gcCause.cpp | 4 +- src/hotspot/share/gc/shared/gcCause.hpp | 2 +- .../gc/shenandoah/shenandoahConcurrentGC.hpp | 1 + .../shenandoah/shenandoahConcurrentMark.cpp | 2 +- .../gc/shenandoah/shenandoahControlThread.cpp | 24 ++++---- .../gc/shenandoah/shenandoahControlThread.hpp | 1 + .../shenandoah/shenandoahJFRObjectCountGC.cpp | 57 +++++++++++++++++++ ...tGC.hpp => shenandoahJFRObjectCountGC.hpp} | 12 +++- .../share/gc/shenandoah/shenandoahMark.cpp | 2 +- .../gc/shenandoah/shenandoahObjectCountGC.cpp | 25 -------- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 2 +- .../gc/shenandoah/shenandoah_globals.hpp | 2 +- .../gc/objectcount/ObjectCountEvent.java | 6 +- .../TestObjectCountEventWithShenandoah.java | 2 +- 14 files changed, 93 insertions(+), 49 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp rename src/hotspot/share/gc/shenandoah/{shenandoahObjectCountGC.hpp => shenandoahJFRObjectCountGC.hpp} (51%) delete mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp diff --git a/src/hotspot/share/gc/shared/gcCause.cpp b/src/hotspot/share/gc/shared/gcCause.cpp index e18262c00cb6a..0eb8b31eabc73 100644 --- a/src/hotspot/share/gc/shared/gcCause.cpp +++ b/src/hotspot/share/gc/shared/gcCause.cpp @@ -95,8 +95,8 @@ const char* GCCause::to_string(GCCause::Cause cause) { case _shenandoah_allocation_failure_evac: return "Allocation Failure During Evacuation"; - case _shenandoah_object_count: - return "Object Count Event Enabled"; + case _shenandoah_jfr_object_count: + return "JFR Object Count Event Enabled"; case _shenandoah_humongous_allocation_failure: return "Humongous Allocation Failure"; diff --git a/src/hotspot/share/gc/shared/gcCause.hpp b/src/hotspot/share/gc/shared/gcCause.hpp index 2a3923cad5e30..d71ed894c6dc9 100644 --- a/src/hotspot/share/gc/shared/gcCause.hpp +++ b/src/hotspot/share/gc/shared/gcCause.hpp @@ -76,7 +76,7 @@ class GCCause : public AllStatic { _shenandoah_humongous_allocation_failure, _shenandoah_concurrent_gc, _shenandoah_upgrade_to_full_gc, - _shenandoah_object_count, + _shenandoah_jfr_object_count, _z_timer, _z_warmup, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp index d90e29a49d833..cd93c79f4911a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.hpp @@ -57,6 +57,7 @@ class ShenandoahConcurrentGC : public ShenandoahGC { public: ShenandoahConcurrentGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap); + // ShenandoahJFRObjectCountGC will override ShenandoahConcurrentGC's collect method if enabled. virtual bool collect(GCCause::Cause cause) override; ShenandoahDegenPoint degen_point() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 50f45c82f7b78..35dbeab8bfde8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -174,7 +174,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { nullptr : _old_queue_set->queue(worker_id); // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event() || + const bool object_count_enabled = ObjectCountEventSender::should_send_event() || ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index d60ddfd5d7039..0fc8364dd6c58 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -36,7 +36,7 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" -#include "gc/shenandoah/shenandoahObjectCountGC.hpp" +#include "gc/shenandoah/shenandoahJFRObjectCountGC.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "logging/log.hpp" #include "memory/metaspaceStats.hpp" @@ -51,7 +51,7 @@ ShenandoahControlThread::ShenandoahControlThread() : } void ShenandoahControlThread::run_service() { - jlong service_start_time = os::javaTimeMillis(); + jlong jfr_event_timestamp = os::javaTimeMillis(); ShenandoahHeap* const heap = ShenandoahHeap::heap(); const GCMode default_mode = concurrent_normal; @@ -68,8 +68,6 @@ void ShenandoahControlThread::run_service() { heap->set_cit(&cit); while (!should_terminate()) { - jlong elapsed_time = os::javaTimeMillis() - service_start_time; - const GCCause::Cause cancelled_cause = heap->cancelled_cause(); if (cancelled_cause == GCCause::_shenandoah_stop_vm) { break; @@ -135,7 +133,7 @@ void ShenandoahControlThread::run_service() { const bool gc_requested = (mode != none); assert (!gc_requested || cause != GCCause::_last_gc_cause, "GC cause should be set"); - + if (gc_requested) { // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(heap); @@ -181,6 +179,9 @@ void ShenandoahControlThread::run_service() { // If this cycle completed without being cancelled, notify waiters about it if (!heap->cancelled_gc()) { + if (ObjectCountEventSender::should_send_event()) { + jfr_event_timestamp = os::javaTimeMillis(); + } notify_alloc_failure_waiters(); } @@ -237,15 +238,17 @@ void ShenandoahControlThread::run_service() { // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); } else { - if (ObjectCountEventSender::should_send_event() && (ShenandoahObjectCountInterval - elapsed_time) <= 0) { + if (ObjectCountEventSender::should_send_event() && + (os::javaTimeMillis() - jfr_event_timestamp > (jlong) ShenandoahJFRObjectCountInterval)) { GCIdMark gc_id_mark; - const GCCause::Cause count_clause = GCCause::_shenandoah_object_count; - service_object_count_cycle(count_clause); + const GCCause::Cause count_cause = GCCause::_shenandoah_jfr_object_count; + service_object_count_cycle(count_cause); // Reset GC Cycle heap->phase_timings()->flush_par_workers_to_cycle(); heap->phase_timings()->flush_cycle_to_global(); - service_start_time = os::javaTimeMillis(); + + jfr_event_timestamp = os::javaTimeMillis(); } } @@ -382,11 +385,12 @@ void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause void ShenandoahControlThread::service_object_count_cycle(GCCause::Cause cause) { ShenandoahHeap* heap = ShenandoahHeap::heap(); + // Create a GC Session so marking will work ShenandoahGCSession session(cause, heap->global_generation()); TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); - ShenandoahObjectCountGC gc(heap->global_generation()); + ShenandoahJFRObjectCountGC gc(heap->global_generation()); if (gc.collect(cause)) { heap->tracer()->report_object_count(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index 7c65fdaccb71b..c0b44c6baac2d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -61,6 +61,7 @@ class ShenandoahControlThread: public ShenandoahController { void service_concurrent_normal_cycle(GCCause::Cause cause); void service_stw_full_cycle(GCCause::Cause cause); void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point); + // Service cycle for counting live objects void service_object_count_cycle(GCCause::Cause cause); void notify_gc_waiters(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp new file mode 100644 index 0000000000000..c6443650509d1 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp @@ -0,0 +1,57 @@ +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahJFRObjectCountGC.hpp" +#include "prims/jvmtiTagMap.hpp" +#include "gc/shenandoah/shenandoahVerifier.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" +#include "gc/shenandoah/shenandoahUtils.hpp" + +void ShenandoahJFRObjectCountGC::op_final_mark() { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should be at safepoint"); + assert(!heap->has_forwarded_objects(), "No forwarded objects on this path"); + + if (ShenandoahVerify) { + heap->verifier()->verify_roots_no_forwarded(); + } + + if (!heap->cancelled_gc()) { + _mark.finish_mark(); + + // Notify JVMTI that the tagmap table will need cleaning. + JvmtiTagMap::set_needs_cleaning(); + + if (ShenandoahVerify) { + ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_mark_verify); + heap->verifier()->verify_after_concmark(); + } + } + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } +} + +bool ShenandoahJFRObjectCountGC::collect(GCCause::Cause cause) { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + + entry_reset(); + + vmop_entry_init_mark(); + + entry_scan_remembered_set(); + + entry_mark_roots(); + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_roots)) { + return false; + } + + entry_mark(); + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { + return false; + } + + vmop_entry_final_mark(); + entry_reset_after_collect(); + return true; +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp similarity index 51% rename from src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp rename to src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp index c927268599558..28d7d32fc267f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp @@ -7,11 +7,19 @@ #include "gc/shenandoah/shenandoahGC.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" -class ShenandoahObjectCountGC : public ShenandoahConcurrentGC { +// A pseudo Shenandoah GC where only the marking phase is initiated +// Without any memory reclamation. This GC is used specifically for +// The Java Flight Recorder's ObjectCount event. +class ShenandoahJFRObjectCountGC : public ShenandoahConcurrentGC { public: - ShenandoahObjectCountGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap = false) + ShenandoahJFRObjectCountGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap = false) : ShenandoahConcurrentGC(generation, do_old_gc_bootstrap) {} + + // Only make use of the mark phase in Shenandoah and does not reclaim any garbage bool collect(GCCause::Cause cause) override; + + protected: + void op_final_mark() override; }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index fbbc26c83d51e..5903032af0fdf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -70,7 +70,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe mark_loop_work(&cl, ld, w, t, req); } else { // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event() || + const bool object_count_enabled = ObjectCountEventSender::should_send_event() || ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp deleted file mode 100644 index 58a036a401db7..0000000000000 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountGC.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahObjectCountGC.hpp" - -bool ShenandoahObjectCountGC::collect(GCCause::Cause cause) { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); - - entry_reset(); - vmop_entry_init_mark(); - - // TASKQUEUE_STATS_ONLY(_mark.task_queues()->reset_taskqueue_stats()); - - entry_scan_remembered_set(); - entry_mark_roots(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_roots)) { - return false; - } - - entry_mark(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { - return false; - } - - entry_reset_after_collect(); - return true; -} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 3cf10e78eb9f6..17812649d166a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -124,7 +124,7 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { switch (_generation->type()) { case NON_GEN: { // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event() || + const bool object_count_enabled = ObjectCountEventSender::should_send_event() || ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 4d6acb379c998..48e3585b8ccc1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -531,7 +531,7 @@ "0 will allow back to back young collections to run during old " \ "collections.") \ \ - product(uintx, ShenandoahObjectCountInterval, 0, \ + product(uintx, ShenandoahJFRObjectCountInterval, 0, \ "Duration in milliseconds to run object counting GC cycles. " \ "0 means disabled.") \ range(0, max_uintx) \ diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index 6f939505bc9e5..aa6862b10fba4 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -27,13 +27,11 @@ public static void test(String gcName) throws Exception { recording.start(); Path tempFile = Path.of("temp.jfr"); - // if temp file exists, assertion + Asserts.assertFalse(Files.exists(tempFile), "File already exists."); recording.dump(tempFile); // Forces chunk rotation System.gc(); recording.stop(); - // Files.deleteIfExists(tempFile); - System.out.println("gcName=" + gcName); List events = Events.fromRecording(recording); for (RecordedEvent event : events) { @@ -57,7 +55,7 @@ public static void test(String gcName) throws Exception { System.out.println("Found heapSummaryEvent: " + heapSummaryEvent.get()); Events.assertField(heapSummaryEvent.get(), "heapUsed").atLeast(0L).getValue(); - // ObjectCountEventVerifier.verify(objCountEvents); + ObjectCountEventVerifier.verify(objCountEvents); } private static boolean isMySystemGc(RecordedEvent event, String gcName) { diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java index 1a057d5251668..af589a9c30b30 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java @@ -8,7 +8,7 @@ * @requires (vm.gc == "Shenandoah" | vm.gc == null) * & vm.opt.ExplicitGCInvokesConcurrent != false * @library /test/lib /test/jdk - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahObjectCountInterval=300 -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEventWithShenandoah + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -XX:ShenandoahJFRObjectCountInterval=300 -XX:+ExplicitGCInvokesConcurrent -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountEventWithShenandoah */ public class TestObjectCountEventWithShenandoah { public static void main(String[] args) throws Exception { From 64db80e866d26f51f2e8c968ab85a4e9f388b06c Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 18 Aug 2025 19:00:51 +0000 Subject: [PATCH 6/9] Restructured ObjectCountEventSenderClosure functionality --- .../share/gc/shared/gcTrace.inline.hpp | 5 +- .../gc/shenandoah/shenandoahControlThread.cpp | 9 ++- .../shenandoah/shenandoahJfrObjectCountGC.cpp | 57 +++++++++++++++++++ .../shenandoah/shenandoahJfrObjectCountGC.hpp | 25 ++++++++ src/hotspot/share/memory/heapInspection.cpp | 7 ++- src/hotspot/share/memory/heapInspection.hpp | 6 +- 6 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.cpp create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.hpp diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index dc84fc026b459..28fc9926a0694 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -27,8 +27,10 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); - _cit->delete_entry(entry, &_total_size_in_words); } + // Delete the entry even if we don't send it. This ensure live objects that + // weren't sent in a previous event emission are not monotonically increasing. + _cit->delete_entry(entry); } private: @@ -50,6 +52,7 @@ void GCTracer::report_object_count() { if (!cit->allocation_failed()) { ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); + cit->reset_size_of_instances_in_words(); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 0fc8364dd6c58..1fafcd02a2afd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -36,7 +36,7 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" -#include "gc/shenandoah/shenandoahJFRObjectCountGC.hpp" +#include "gc/shenandoah/shenandoahJfrObjectCountGC.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "logging/log.hpp" #include "memory/metaspaceStats.hpp" @@ -241,6 +241,11 @@ void ShenandoahControlThread::run_service() { if (ObjectCountEventSender::should_send_event() && (os::javaTimeMillis() - jfr_event_timestamp > (jlong) ShenandoahJFRObjectCountInterval)) { GCIdMark gc_id_mark; + + // Do not increment the GC ID: + // size_t current_gc_id = get_gc_id(); + // GCIdMark gc_id_mark(get_gc_id()); + const GCCause::Cause count_cause = GCCause::_shenandoah_jfr_object_count; service_object_count_cycle(count_cause); @@ -390,7 +395,7 @@ void ShenandoahControlThread::service_object_count_cycle(GCCause::Cause cause) { TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); - ShenandoahJFRObjectCountGC gc(heap->global_generation()); + ShenandoahJfrObjectCountGC gc(heap->global_generation()); if (gc.collect(cause)) { heap->tracer()->report_object_count(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.cpp new file mode 100644 index 0000000000000..4bb3481a6ca88 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.cpp @@ -0,0 +1,57 @@ +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahJfrObjectCountGC.hpp" +#include "prims/jvmtiTagMap.hpp" +#include "gc/shenandoah/shenandoahVerifier.hpp" +#include "gc/shenandoah/shenandoahPhaseTimings.hpp" +#include "gc/shenandoah/shenandoahUtils.hpp" + +void ShenandoahJfrObjectCountGC::op_final_mark() { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should be at safepoint"); + assert(!heap->has_forwarded_objects(), "No forwarded objects on this path"); + + if (ShenandoahVerify) { + heap->verifier()->verify_roots_no_forwarded(); + } + + if (!heap->cancelled_gc()) { + _mark.finish_mark(); + + // Notify JVMTI that the tagmap table will need cleaning. + JvmtiTagMap::set_needs_cleaning(); + + if (ShenandoahVerify) { + ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_mark_verify); + heap->verifier()->verify_after_concmark(); + } + } + + { + ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_propagate_gc_state); + heap->propagate_gc_state_to_all_threads(); + } +} + +bool ShenandoahJfrObjectCountGC::collect(GCCause::Cause cause) { + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + + entry_reset(); + + vmop_entry_init_mark(); + + entry_scan_remembered_set(); + + entry_mark_roots(); + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_roots)) { + return false; + } + + entry_mark(); + if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { + return false; + } + + vmop_entry_final_mark(); + entry_reset_after_collect(); + return true; +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.hpp new file mode 100644 index 0000000000000..a7479093f534b --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahJfrObjectCountGC.hpp @@ -0,0 +1,25 @@ +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP + +#include "gc/shared/gcCause.hpp" +#include "gc/shenandoah/shenandoahConcurrentGC.hpp" +#include "gc/shenandoah/shenandoahConcurrentMark.hpp" +#include "gc/shenandoah/shenandoahGC.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" + +// A pseudo Shenandoah GC where only the marking phase is initiated +// without any memory reclamation. This GC is used specifically for +// the Java Flight Recorder's ObjectCount event. +class ShenandoahJfrObjectCountGC : public ShenandoahConcurrentGC { + public: + ShenandoahJfrObjectCountGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap = false) + : ShenandoahConcurrentGC(generation, do_old_gc_bootstrap) {} + + // Only make use of the mark phase in Shenandoah and does not reclaim any garbage + bool collect(GCCause::Cause cause) override; + + protected: + void op_final_mark() override; +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 3350104ceaf6a..4885ad6f07030 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -280,11 +280,14 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { return false; } -void KlassInfoTable::delete_entry(KlassInfoEntry* entry, size_t* total_table_size) { +void KlassInfoTable::reset_size_of_instances_in_words() { + _size_of_instances_in_words = 0; +} + +void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { uint idx = hash(entry->klass()) % _num_buckets; size_t total_entry_size = entry->words(); _buckets[idx].remove_from_list(entry); - *total_table_size -= total_entry_size; } class KlassInfoTableMergeClosure : public KlassInfoClosure { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 5058e29a8dacc..3371bef0a0393 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -132,7 +132,11 @@ class KlassInfoTable: public StackObj { bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); // Deletes the KlassInfoEntry in the list - void delete_entry(KlassInfoEntry* entry, size_t* total_table_size); + void delete_entry(KlassInfoEntry* entry); + // Reset the size of instances in words to 0. Only call this method + // after sending the KlassInfoTable for the ObjectCount or + // ObjectCountAfterGC event and deleting it's entries. + void reset_size_of_instances_in_words(); friend class KlassInfoHisto; friend class KlassHierarchy; }; From ad1b068a5ae9d365972cf74a45696aa379fac993 Mon Sep 17 00:00:00 2001 From: pf0n Date: Mon, 18 Aug 2025 12:08:04 -0700 Subject: [PATCH 7/9] Delete src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp --- .../shenandoah/shenandoahJFRObjectCountGC.cpp | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp deleted file mode 100644 index c6443650509d1..0000000000000 --- a/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahJFRObjectCountGC.hpp" -#include "prims/jvmtiTagMap.hpp" -#include "gc/shenandoah/shenandoahVerifier.hpp" -#include "gc/shenandoah/shenandoahPhaseTimings.hpp" -#include "gc/shenandoah/shenandoahUtils.hpp" - -void ShenandoahJFRObjectCountGC::op_final_mark() { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); - assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should be at safepoint"); - assert(!heap->has_forwarded_objects(), "No forwarded objects on this path"); - - if (ShenandoahVerify) { - heap->verifier()->verify_roots_no_forwarded(); - } - - if (!heap->cancelled_gc()) { - _mark.finish_mark(); - - // Notify JVMTI that the tagmap table will need cleaning. - JvmtiTagMap::set_needs_cleaning(); - - if (ShenandoahVerify) { - ShenandoahTimingsTracker v(ShenandoahPhaseTimings::final_mark_verify); - heap->verifier()->verify_after_concmark(); - } - } - - { - ShenandoahTimingsTracker timing(ShenandoahPhaseTimings::final_mark_propagate_gc_state); - heap->propagate_gc_state_to_all_threads(); - } -} - -bool ShenandoahJFRObjectCountGC::collect(GCCause::Cause cause) { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); - - entry_reset(); - - vmop_entry_init_mark(); - - entry_scan_remembered_set(); - - entry_mark_roots(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_roots)) { - return false; - } - - entry_mark(); - if (check_cancellation_and_abort(ShenandoahDegenPoint::_degenerated_mark)) { - return false; - } - - vmop_entry_final_mark(); - entry_reset_after_collect(); - return true; -} From acc66302b7000b580190259d4bf71b23a9deaef5 Mon Sep 17 00:00:00 2001 From: pf0n Date: Mon, 18 Aug 2025 12:08:27 -0700 Subject: [PATCH 8/9] Delete src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp --- .../shenandoah/shenandoahJFRObjectCountGC.hpp | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp diff --git a/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp b/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp deleted file mode 100644 index 28d7d32fc267f..0000000000000 --- a/src/hotspot/share/gc/shenandoah/shenandoahJFRObjectCountGC.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP -#define SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP - -#include "gc/shared/gcCause.hpp" -#include "gc/shenandoah/shenandoahConcurrentGC.hpp" -#include "gc/shenandoah/shenandoahConcurrentMark.hpp" -#include "gc/shenandoah/shenandoahGC.hpp" -#include "gc/shenandoah/shenandoahHeap.hpp" - -// A pseudo Shenandoah GC where only the marking phase is initiated -// Without any memory reclamation. This GC is used specifically for -// The Java Flight Recorder's ObjectCount event. -class ShenandoahJFRObjectCountGC : public ShenandoahConcurrentGC { - public: - ShenandoahJFRObjectCountGC(ShenandoahGeneration* generation, bool do_old_gc_bootstrap = false) - : ShenandoahConcurrentGC(generation, do_old_gc_bootstrap) {} - - // Only make use of the mark phase in Shenandoah and does not reclaim any garbage - bool collect(GCCause::Cause cause) override; - - protected: - void op_final_mark() override; -}; - -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTGC_HPP From 3f550b142cbca5a55167d1bda007db1043f1ca57 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 18 Aug 2025 23:00:01 +0000 Subject: [PATCH 9/9] Removed unnecessary line in delete_entry --- src/hotspot/share/memory/heapInspection.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 4885ad6f07030..d728b85640f0e 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -286,7 +286,6 @@ void KlassInfoTable::reset_size_of_instances_in_words() { void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { uint idx = hash(entry->klass()) % _num_buckets; - size_t total_entry_size = entry->words(); _buckets[idx].remove_from_list(entry); }