From 3da9f8936750291fc59346a3c89a3dd76c8346bc Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 9 Jul 2025 19:13:19 +0000 Subject: [PATCH 01/26] Testing ObjectCount event with Shenandoah collector --- .../TestObjectCountEventWithShenandoah.java | 17 +++ test/lib/jdk/test/lib/jfr/GCHelper.java | 111 ++++++++++-------- 2 files changed, 82 insertions(+), 46 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java new file mode 100644 index 0000000000000..777230a16ab4a --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java @@ -0,0 +1,17 @@ +package jdk.jfr.event.gc.objectcount; +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @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 + */ +public class TestObjectCountEventWithShenandoah { + public static void main(String[] args) throws Exception { + ObjectCountAfterGCEvent.test(GCHelper.gcShenandoah); + } +} diff --git a/test/lib/jdk/test/lib/jfr/GCHelper.java b/test/lib/jdk/test/lib/jfr/GCHelper.java index 07c6c1e1ce550..aee67c6f4add2 100644 --- a/test/lib/jdk/test/lib/jfr/GCHelper.java +++ b/test/lib/jdk/test/lib/jfr/GCHelper.java @@ -74,6 +74,7 @@ public class GCHelper { public static final String gcPSMarkSweep = "PSMarkSweep"; public static final String gcParallelOld = "ParallelOld"; public static final String pauseLevelEvent = "GCPhasePauseLevel"; + public static final String gcShenandoah = "Shenandoah"; private static final List g1HeapRegionTypes; private static final List shenandoahHeapRegionStates; @@ -92,20 +93,22 @@ public static boolean isGcEvent(RecordedEvent event) { return false; } -// public static String getEventDesc(RecordedEvent event) { -// final String path = event.getEventType().getName(); -// if (!isGcEvent(event)) { -// return path; -// } -// if (event_garbage_collection.equals(path)) { -// String name = Events.assertField(event, "name").getValue(); -// String cause = Events.assertField(event, "cause").getValue(); -// return String.format("path=%s, gcId=%d, endTime=%d, name=%s, cause=%s, startTime=%d", -// path, getGcId(event), event.getEndTime(), name, cause, event.getStartTime()); -// } else { -// return String.format("path=%s, gcId=%d, endTime=%d", path, getGcId(event), event.getEndTime()); -// } -// } + // public static String getEventDesc(RecordedEvent event) { + // final String path = event.getEventType().getName(); + // if (!isGcEvent(event)) { + // return path; + // } + // if (event_garbage_collection.equals(path)) { + // String name = Events.assertField(event, "name").getValue(); + // String cause = Events.assertField(event, "cause").getValue(); + // return String.format("path=%s, gcId=%d, endTime=%d, name=%s, cause=%s, + // startTime=%d", + // path, getGcId(event), event.getEndTime(), name, cause, event.getStartTime()); + // } else { + // return String.format("path=%s, gcId=%d, endTime=%d", path, getGcId(event), + // event.getEndTime()); + // } + // } public static RecordedEvent getConfigEvent(List events) throws Exception { for (RecordedEvent event : events) { @@ -177,40 +180,50 @@ public static List removeFirstAndLastGC(List event beanCollectorTypes.put("PS MarkSweep", false); beanCollectorTypes.put("MarkSweepCompact", false); - // List of expected collector overrides. "A.B" means that collector A may use collector B. + // List of expected collector overrides. "A.B" means that collector A may use + // collector B. collectorOverrides.add("G1Old.G1Full"); collectorOverrides.add("SerialOld.PSMarkSweep"); - requiredEvents.put(gcG1New, new String[] {event_heap_summary, event_young_garbage_collection}); - requiredEvents.put(gcDefNew, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_young_garbage_collection}); - requiredEvents.put(gcParallelScavenge, new String[] {event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, event_reference_statistics, event_phases_pause, event_phases_level_1, event_young_garbage_collection}); - requiredEvents.put(gcG1Old, new String[] {event_heap_summary, event_old_garbage_collection}); - requiredEvents.put(gcG1Full, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_old_garbage_collection}); - requiredEvents.put(gcSerialOld, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_old_garbage_collection}); - requiredEvents.put(gcParallelOld, new String[] {event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, event_reference_statistics, event_phases_pause, event_phases_level_1, event_old_garbage_collection, event_parold_garbage_collection}); + requiredEvents.put(gcG1New, new String[] { event_heap_summary, event_young_garbage_collection }); + requiredEvents.put(gcDefNew, new String[] { event_heap_summary, event_heap_metaspace_summary, + event_phases_pause, event_phases_level_1, event_young_garbage_collection }); + requiredEvents.put(gcParallelScavenge, + new String[] { event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, + event_reference_statistics, event_phases_pause, event_phases_level_1, + event_young_garbage_collection }); + requiredEvents.put(gcG1Old, new String[] { event_heap_summary, event_old_garbage_collection }); + requiredEvents.put(gcG1Full, new String[] { event_heap_summary, event_heap_metaspace_summary, + event_phases_pause, event_phases_level_1, event_old_garbage_collection }); + requiredEvents.put(gcSerialOld, new String[] { event_heap_summary, event_heap_metaspace_summary, + event_phases_pause, event_phases_level_1, event_old_garbage_collection }); + requiredEvents.put(gcParallelOld, + new String[] { event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, + event_reference_statistics, event_phases_pause, event_phases_level_1, + event_old_garbage_collection, event_parold_garbage_collection }); String[] g1HeapRegionTypeLiterals = new String[] { - "Free", - "Eden", - "Survivor", - "Starts Humongous", - "Continues Humongous", - "Old" - }; + "Free", + "Eden", + "Survivor", + "Starts Humongous", + "Continues Humongous", + "Old" + }; g1HeapRegionTypes = Collections.unmodifiableList(Arrays.asList(g1HeapRegionTypeLiterals)); String[] shenandoahHeapRegionStateLiterals = new String[] { - "Empty Uncommitted", - "Empty Committed", - "Regular", - "Humongous Start", - "Humongous Continuation", - "Humongous Start, Pinned", - "Collection Set", - "Pinned", - "Collection Set, Pinned", - "Trash" + "Empty Uncommitted", + "Empty Committed", + "Regular", + "Humongous Start", + "Humongous Continuation", + "Humongous Start, Pinned", + "Collection Set", + "Pinned", + "Collection Set, Pinned", + "Trash" }; shenandoahHeapRegionStates = Collections.unmodifiableList(Arrays.asList(shenandoahHeapRegionStateLiterals)); @@ -245,8 +258,10 @@ public boolean addEvent(RecordedEvent event) { } boolean isEndEvent = event_garbage_collection.equals(event.getEventType().getName()); if (isEndEvent) { - // Verify that we have not already got a garbage_collection event with this gcId. - assertNull(getEndEvent(), String.format("Multiple %s for gcId %d", event_garbage_collection, getGcId())); + // Verify that we have not already got a garbage_collection event with this + // gcId. + assertNull(getEndEvent(), + String.format("Multiple %s for gcId %d", event_garbage_collection, getGcId())); } events.add(event); return isEndEvent; @@ -339,7 +354,8 @@ public static List createFromEvents(List events) throws openGcIds.pop(); } } - // Verify that all start_garbage_collection events have received a corresponding "garbage_collection" event. + // Verify that all start_garbage_collection events have received a corresponding + // "garbage_collection" event. for (GcBatch batch : batches) { if (batch.getEndEvent() == null) { System.out.println(batch.getLog()); @@ -351,7 +367,8 @@ public static List createFromEvents(List events) throws } /** - * Contains number of collections and sum pause time for young and old collections. + * Contains number of collections and sum pause time for young and old + * collections. */ public static class CollectionSummary { public long collectionCountOld; @@ -391,7 +408,7 @@ public CollectionSummary calcDelta(CollectionSummary prev) { public static CollectionSummary createFromMxBeans() { CollectionSummary summary = new CollectionSummary(); List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); - for (int c=0; c Date: Wed, 9 Jul 2025 21:59:41 +0000 Subject: [PATCH 02/26] Created ObjectCount event tests for G1Full and ParallelOld --- .../gc/objectcount/ObjectCountEvent.java | 67 +++++++++++++++++++ ...tObjectCountEventWithG1FullCollection.java | 23 +++++++ .../TestObjectCountEventWithParallelOld.java | 21 ++++++ .../TestObjectCountEventWithShenandoah.java | 2 +- test/lib/jdk/test/lib/jfr/EventNames.java | 2 +- 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java create mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java create mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java new file mode 100644 index 0000000000000..b8c44555ad927 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -0,0 +1,67 @@ +package jdk.jfr.event.gc.objectcount; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +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; + private static final String heapSummaryEventPath = EventNames.GCHeapSummary; + + public static void test(String gcName) throws Exception { + Recording recording = new Recording(); + recording.enable(objectCountEventPath); + recording.enable(gcEventPath); + recording.enable(heapSummaryEventPath); + + ObjectCountEventVerifier.createTestData(); + recording.start(); + ObjectCountEventVerifier.createTestData(); + + Path tempFile = Path.of("temp.jfr"); + recording.dump(tempFile); // Forces chunk rotation + recording.stop(); + + Files.deleteIfExists(tempFile); + + System.out.println("gcName=" + gcName); + List events = Events.fromRecording(recording); + for (RecordedEvent event : events) { + System.out.println("Event: " + event); + } + + Optional gcEvent = events.stream() + .filter(e -> isMySystemGc(e, gcName)) + .findFirst(); + + List objCountEvents = events.stream() + .filter(e -> Events.isEventType(e, objectCountEventPath)) + .collect(Collectors.toList()); + Asserts.assertFalse(objCountEvents.isEmpty(), "No objCountEvents"); + + Optional heapSummaryEvent = events.stream() + .filter(e -> Events.isEventType(e, heapSummaryEventPath)) + .filter(e -> "After GC".equals(Events.assertField(e, "when").getValue())) + .findFirst(); + Asserts.assertTrue(heapSummaryEvent.isPresent(), "No heapSummary"); + System.out.println("Found heapSummaryEvent: " + heapSummaryEvent.get()); + + Events.assertField(heapSummaryEvent.get(), "heapUsed").atLeast(0L).getValue(); + ObjectCountEventVerifier.verify(objCountEvents); + } + + private static boolean isMySystemGc(RecordedEvent event, String gcName) { + return Events.isEventType(event, gcEventPath) && + gcName.equals(Events.assertField(event, "name").getValue()) && + "System.gc()".equals(Events.assertField(event, "cause").getValue()); + } +} diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java new file mode 100644 index 0000000000000..bb9f24aaa0260 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java @@ -0,0 +1,23 @@ + +package jdk.jfr.event.gc.objectcount; + +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires (vm.gc == "G1" | vm.gc == null) + * & vm.opt.ExplicitGCInvokesConcurrent != true + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:-UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:MarkSweepDeadRatio=0 + * -XX:-UseCompressedOops -XX:-UseCompressedClassPointers + * -XX:+IgnoreUnrecognizedVMOptions + * jdk.jfr.event.gc.objectcount.TestObjectCountEventWithG1FullCollection + */ +public class TestObjectCountEventWithG1FullCollection { + public static void main(String[] args) throws Exception { + ObjectCountEvent.test(GCHelper.gcG1Full); + } +} diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java new file mode 100644 index 0000000000000..421c356a31579 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java @@ -0,0 +1,21 @@ +package jdk.jfr.event.gc.objectcount; + +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @requires vm.gc == "Parallel" | vm.gc == null + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -XX:-UseFastUnorderedTimeStamps -XX:+UseParallelGC + * -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops + * -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions + * jdk.jfr.event.gc.objectcount.TestObjectCountEventWithParallelOld + */ +public class TestObjectCountEventWithParallelOld { + public static void main(String[] args) throws Exception { + ObjectCountEvent.test(GCHelper.gcParallelOld); + } +} diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java index 777230a16ab4a..3191ebb43d3f2 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java @@ -12,6 +12,6 @@ */ public class TestObjectCountEventWithShenandoah { public static void main(String[] args) throws Exception { - ObjectCountAfterGCEvent.test(GCHelper.gcShenandoah); + ObjectCountEvent.test(GCHelper.gcShenandoah); } } diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index a00898358a865..a5b27b5fab59a 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -197,7 +197,7 @@ public class EventNames { public static final String ResidentSetSize = PREFIX + "ResidentSetSize"; // JDK - public static final String FileForce = PREFIX + "FileForce"; + public static final String FileForce = PREFIX + "FileForce"; public static final String FileRead = PREFIX + "FileRead"; public static final String FileWrite = PREFIX + "FileWrite"; public static final String SocketRead = PREFIX + "SocketRead"; From 354deee56a9eeed6bad1d0ef1997c3c05a1d7eb4 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 9 Jul 2025 23:07:01 +0000 Subject: [PATCH 03/26] Initiated GC for ObjectCount testing --- test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index b8c44555ad927..3487bf7bba0cd 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -29,6 +29,7 @@ public static void test(String gcName) throws Exception { Path tempFile = Path.of("temp.jfr"); recording.dump(tempFile); // Forces chunk rotation + System.gc(); recording.stop(); Files.deleteIfExists(tempFile); From 359caff2a25f6eefdc1749047a5eebb55d148d47 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 10 Jul 2025 16:45:58 +0000 Subject: [PATCH 04/26] Removed unnecessary duplicate calls to ObjectCountEventVerifier in ObjectCountEvent --- test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index 3487bf7bba0cd..30d9e141d8285 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -25,7 +25,6 @@ public static void test(String gcName) throws Exception { ObjectCountEventVerifier.createTestData(); recording.start(); - ObjectCountEventVerifier.createTestData(); Path tempFile = Path.of("temp.jfr"); recording.dump(tempFile); // Forces chunk rotation From adea2fc6f4d8e049a2d41191276108fd1197c328 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 14 Jul 2025 19:08:07 +0000 Subject: [PATCH 05/26] ObjectCount event test with g1 full --- .../gc/objectcount/TestObjectCountEventWithG1FullCollection.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java index bb9f24aaa0260..cd70c05239ccb 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java @@ -1,4 +1,3 @@ - package jdk.jfr.event.gc.objectcount; import jdk.test.lib.jfr.GCHelper; From c5356458407186513688032348cbe568739cfe67 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 15 Jul 2025 21:01:41 +0000 Subject: [PATCH 06/26] Separated ObjectCount and ObjectCountAfterGC --- .../shared/objectCountAfterGCEventSender.cpp | 74 +++++++++++++++++++ .../shared/objectCountAfterGCEventSender.hpp | 55 ++++++++++++++ .../gc/shared/objectCountEventSender.cpp | 3 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 5 ++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp create mode 100644 src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp diff --git a/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp b/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp new file mode 100644 index 0000000000000..269f59d6718c5 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#include "gc/shared/gcId.hpp" +#include "gc/shared/objectCountAfterGCEventSender.hpp" +#include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" +#include "utilities/macros.hpp" +#include "utilities/ticks.hpp" +#if INCLUDE_SERVICES + +bool ObjectCountAfterGCEventSender::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + +bool ObjectCountAfterGCEventSender::_should_send_requestable_event = false; + +void ObjectCountAfterGCEventSender::enable_requestable_event() { + _should_send_requestable_event = true; +} + +void ObjectCountAfterGCEventSender::disable_requestable_event() { + _should_send_requestable_event = false; +} + +template +void ObjectCountAfterGCEventSender::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(); + } +} + +void ObjectCountAfterGCEventSender::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(klass, count, total_size, timestamp); +} + +#endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp b/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp new file mode 100644 index 0000000000000..255f25a7c7ab4 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_OBJECTCOUNTAFTERGCEVENTSENDER_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTAFTERGCEVENTSENDER_HPP + +#include "gc/shared/gcTrace.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#include "utilities/ticks.hpp" + +#if INCLUDE_SERVICES + +class KlassInfoEntry; +class Klass; + +class ObjectCountAfterGCEventSender : public AllStatic { + static bool _should_send_requestable_event; + + template + 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(); + + static void send(const KlassInfoEntry* entry, const Ticks& timestamp); + static bool should_send_event(); +}; + +#endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index a28c52e5c901d..141069a71251b 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -33,7 +33,7 @@ bool ObjectCountEventSender::should_send_event() { #if INCLUDE_JFR - return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); + return _should_send_requestable_event || EventObjectCount::is_enabled(); #else return false; #endif // INCLUDE_JFR @@ -69,7 +69,6 @@ void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& time julong total_size = entry->words() * BytesPerWord; send_event_if_enabled(klass, count, total_size, timestamp); - send_event_if_enabled(klass, count, total_size, timestamp); } #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 2f264cae70f19..fbe65b692eb3f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -28,6 +28,7 @@ #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/collectorCounters.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" +#include "gc/shared/gcTrace.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -35,6 +36,7 @@ #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" @@ -770,6 +772,9 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->verifier()->verify_roots_no_forwarded(); } + ShenandoahIsAliveClosure is_alive; + ShenandoahHeap::heap()->tracer()->report_object_count(&is_alive, ShenandoahHeap::heap()->workers()); + if (!heap->cancelled_gc()) { _mark.finish_mark(); assert(!heap->cancelled_gc(), "STW mark cannot OOM"); From a135b2ddfa061e478969194574ec8a7489f02404 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 16 Jul 2025 19:41:06 +0000 Subject: [PATCH 07/26] Minimize code duplication by adding templates to ObjectCountEvent sender --- .../gc/shared/objectCountEventSender.hpp | 82 ++++++++++++------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 115fbfdaf7d3a..9c35521453008 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -1,33 +1,9 @@ -/* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP -#include "gc/shared/gcTrace.hpp" -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" +#include "gc/shared/gcId.hpp" +#include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" @@ -36,7 +12,8 @@ class KlassInfoEntry; class Klass; -class ObjectCountEventSender : public AllStatic { +template +class ObjectCountEventSenderTemplate : public AllStatic { static bool _should_send_requestable_event; template @@ -50,6 +27,55 @@ class ObjectCountEventSender : public AllStatic { static bool should_send_event(); }; +typedef ObjectCountEventSenderTemplate ObjectCountEventSender; +typedef ObjectCountEventSenderTemplate ObjectCountAfterGCEventSender; + +template +bool ObjectCountEventSenderTemplate::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || EventT::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + +template +bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; + +template +void ObjectCountEventSenderTemplate::enable_requestable_event() { + _should_send_requestable_event = true; +} + + +template +void ObjectCountEventSenderTemplate::disable_requestable_event() { + _should_send_requestable_event = false; +} + +template +template +void ObjectCountEventSenderTemplate::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 +void ObjectCountEventSenderTemplate::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(klass, count, total_size, timestamp); +} #endif // INCLUDE_SERVICES #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP From 48262294e82053a2e5923a4bee011e8bd47b369a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 16 Jul 2025 23:03:23 +0000 Subject: [PATCH 08/26] ObjectCount data will be emitted if ObjectCountAfterGC is sending data --- .../shared/objectCountEventSenderTemplate.hpp | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp new file mode 100644 index 0000000000000..3d07f80745473 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -0,0 +1,86 @@ +#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP + +#include "gc/shared/gcId.hpp" +#include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" +#include "utilities/macros.hpp" +#include "utilities/ticks.hpp" +#include "iostream" + +#if INCLUDE_SERVICES + +class KlassInfoEntry; +class Klass; + +template +class ObjectCountEventSenderTemplate : public AllStatic { + static bool _should_send_requestable_event; + + template + 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(); + + static void send(const KlassInfoEntry* entry, const Ticks& timestamp); + static bool should_send_event(); +}; + +typedef ObjectCountEventSenderTemplate ObjectCountEventSender; +typedef ObjectCountEventSenderTemplate ObjectCountAfterGCEventSender; + +template +bool ObjectCountEventSenderTemplate::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || Event::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + +template +bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; + +template +void ObjectCountEventSenderTemplate::enable_requestable_event() { + _should_send_requestable_event = true; +} + + +template +void ObjectCountEventSenderTemplate::disable_requestable_event() { + _should_send_requestable_event = false; +} + +template +template +void ObjectCountEventSenderTemplate::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 +void ObjectCountEventSenderTemplate::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(klass, count, total_size, timestamp); + // If sending ObjectCountAfterGCEvent, check if ObjectCount is enabled and send event data to ObjectCount + if (std::is_same::value && ObjectCountEventSender::should_send_event()) { + send_event_if_enabled(klass, count, total_size, timestamp); + } +} +#endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP From 00b15d6a9670689caaef21806bc85aa5ad6085a2 Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 16 Jul 2025 16:09:26 -0700 Subject: [PATCH 09/26] Delete src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp --- .../shared/objectCountAfterGCEventSender.cpp | 74 ------------------- 1 file changed, 74 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp diff --git a/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp b/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp deleted file mode 100644 index 269f59d6718c5..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - - -#include "gc/shared/gcId.hpp" -#include "gc/shared/objectCountAfterGCEventSender.hpp" -#include "jfr/jfrEvents.hpp" -#include "memory/heapInspection.hpp" -#include "utilities/macros.hpp" -#include "utilities/ticks.hpp" -#if INCLUDE_SERVICES - -bool ObjectCountAfterGCEventSender::should_send_event() { -#if INCLUDE_JFR - return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); -#else - return false; -#endif // INCLUDE_JFR -} - -bool ObjectCountAfterGCEventSender::_should_send_requestable_event = false; - -void ObjectCountAfterGCEventSender::enable_requestable_event() { - _should_send_requestable_event = true; -} - -void ObjectCountAfterGCEventSender::disable_requestable_event() { - _should_send_requestable_event = false; -} - -template -void ObjectCountAfterGCEventSender::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(); - } -} - -void ObjectCountAfterGCEventSender::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(klass, count, total_size, timestamp); -} - -#endif // INCLUDE_SERVICES From 461b71cf2920e1ea7f8973ef39017a14b939ea64 Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 16 Jul 2025 16:09:38 -0700 Subject: [PATCH 10/26] Delete src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp --- .../shared/objectCountAfterGCEventSender.hpp | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp diff --git a/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp b/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp deleted file mode 100644 index 255f25a7c7ab4..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountAfterGCEventSender.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#ifndef SHARE_GC_SHARED_OBJECTCOUNTAFTERGCEVENTSENDER_HPP -#define SHARE_GC_SHARED_OBJECTCOUNTAFTERGCEVENTSENDER_HPP - -#include "gc/shared/gcTrace.hpp" -#include "memory/allStatic.hpp" -#include "utilities/globalDefinitions.hpp" -#include "utilities/macros.hpp" -#include "utilities/ticks.hpp" - -#if INCLUDE_SERVICES - -class KlassInfoEntry; -class Klass; - -class ObjectCountAfterGCEventSender : public AllStatic { - static bool _should_send_requestable_event; - - template - 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(); - - static void send(const KlassInfoEntry* entry, const Ticks& timestamp); - static bool should_send_event(); -}; - -#endif // INCLUDE_SERVICES - -#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP From 33aa1dad9a3383d26c26d368b19ad0a05d292e6b Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 16 Jul 2025 16:09:45 -0700 Subject: [PATCH 11/26] Delete src/hotspot/share/gc/shared/objectCountEventSender.cpp --- .../gc/shared/objectCountEventSender.cpp | 74 ------------------- 1 file changed, 74 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.cpp diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp deleted file mode 100644 index 141069a71251b..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - - -#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" -#if INCLUDE_SERVICES - -bool ObjectCountEventSender::should_send_event() { -#if INCLUDE_JFR - return _should_send_requestable_event || EventObjectCount::is_enabled(); -#else - return false; -#endif // INCLUDE_JFR -} - -bool ObjectCountEventSender::_should_send_requestable_event = false; - -void ObjectCountEventSender::enable_requestable_event() { - _should_send_requestable_event = true; -} - -void ObjectCountEventSender::disable_requestable_event() { - _should_send_requestable_event = false; -} - -template -void ObjectCountEventSender::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(); - } -} - -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(klass, count, total_size, timestamp); -} - -#endif // INCLUDE_SERVICES From cb368f6e2e810238e99dd46cb7f0f6764bc13b44 Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 16 Jul 2025 16:09:53 -0700 Subject: [PATCH 12/26] Delete src/hotspot/share/gc/shared/objectCountEventSender.hpp --- .../gc/shared/objectCountEventSender.hpp | 81 ------------------- 1 file changed, 81 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.hpp diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp deleted file mode 100644 index 9c35521453008..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP -#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_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 -class ObjectCountEventSenderTemplate : public AllStatic { - static bool _should_send_requestable_event; - - template - 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(); - - static void send(const KlassInfoEntry* entry, const Ticks& timestamp); - static bool should_send_event(); -}; - -typedef ObjectCountEventSenderTemplate ObjectCountEventSender; -typedef ObjectCountEventSenderTemplate ObjectCountAfterGCEventSender; - -template -bool ObjectCountEventSenderTemplate::should_send_event() { -#if INCLUDE_JFR - return _should_send_requestable_event || EventT::is_enabled(); -#else - return false; -#endif // INCLUDE_JFR -} - -template -bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; - -template -void ObjectCountEventSenderTemplate::enable_requestable_event() { - _should_send_requestable_event = true; -} - - -template -void ObjectCountEventSenderTemplate::disable_requestable_event() { - _should_send_requestable_event = false; -} - -template -template -void ObjectCountEventSenderTemplate::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 -void ObjectCountEventSenderTemplate::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(klass, count, total_size, timestamp); -} -#endif // INCLUDE_SERVICES - -#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP From 3d05ece258e2e73a06f9612c7b54f341080647a8 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 17 Jul 2025 16:34:45 +0000 Subject: [PATCH 13/26] Added object counting to Shenandoah --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index fbe65b692eb3f..c983c89c5fdfe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -773,7 +773,7 @@ void ShenandoahConcurrentGC::op_final_mark() { } ShenandoahIsAliveClosure is_alive; - ShenandoahHeap::heap()->tracer()->report_object_count(&is_alive, ShenandoahHeap::heap()->workers()); + heap->tracer()->report_object_count(&is_alive, heap->workers()); if (!heap->cancelled_gc()) { _mark.finish_mark(); From 82bb8838a8a1882077467b963f83673d4d46b13b Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 17 Jul 2025 16:40:34 +0000 Subject: [PATCH 14/26] Templates for ObjectCountEventSenderClosure --- src/hotspot/share/gc/shared/gcTrace.cpp | 26 ++++++++++++++++++++----- src/hotspot/share/gc/shared/gcTrace.hpp | 1 + 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index bad9c707b1e51..8b8d57bffec78 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,7 +27,7 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" @@ -74,6 +74,8 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con } #if INCLUDE_SERVICES + +template class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; const size_t _total_size_in_words; @@ -88,7 +90,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _timestamp); + Event::send(entry, _timestamp); } } @@ -99,9 +101,8 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { +void GCTracer::report_object_count(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { assert(is_alive_cl != nullptr, "Must supply function to check liveness"); - if (ObjectCountEventSender::should_send_event()) { ResourceMark rm; @@ -109,7 +110,22 @@ void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, Work 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 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) { + assert(is_alive_cl != nullptr, "Must supply function to check liveness"); + if (ObjectCountAfterGCEventSender::should_send_event()) { + 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()); cit.iterate(&event_sender); } } diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 6a47e54090f88..2d7366b17e893 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -103,6 +103,7 @@ 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(BoolObjectClosure* object_filter, WorkerThreads* workers) 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; From 405e0d9fb1d7a260f25af530720ba501283ab493 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 17 Jul 2025 16:47:06 +0000 Subject: [PATCH 15/26] Updated file for objectCountEventSenderTemplate.hpp --- src/hotspot/share/jfr/periodic/jfrPeriodic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0be1c32728c08..c478a0a18432a 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -33,7 +33,7 @@ #include "gc/shared/gcConfiguration.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcVMOperations.hpp" -#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" From d1a1e6b859ddf1103e5a0cbd8787f1468bbdfb49 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 17 Jul 2025 22:44:07 +0000 Subject: [PATCH 16/26] Updated header gaurds for objectCountEventSenderTemplate.hpp --- .../share/gc/shared/objectCountEventSenderTemplate.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp index 3d07f80745473..33fe676638890 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -1,5 +1,5 @@ -#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP -#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP +#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP #include "gc/shared/gcId.hpp" #include "jfr/jfrEvents.hpp" @@ -83,4 +83,4 @@ void ObjectCountEventSenderTemplate::send(const KlassInfoEntry* entry, co } #endif // INCLUDE_SERVICES -#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP +#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP From a868e9bff34961ed66491e37eacd9c6a1ad847a7 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 18 Jul 2025 17:49:07 +0000 Subject: [PATCH 17/26] Removed whitespace changes --- test/lib/jdk/test/lib/jfr/EventNames.java | 2 +- test/lib/jdk/test/lib/jfr/GCHelper.java | 111 +++++++++------------- 2 files changed, 47 insertions(+), 66 deletions(-) diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index a5b27b5fab59a..a00898358a865 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -197,7 +197,7 @@ public class EventNames { public static final String ResidentSetSize = PREFIX + "ResidentSetSize"; // JDK - public static final String FileForce = PREFIX + "FileForce"; + public static final String FileForce = PREFIX + "FileForce"; public static final String FileRead = PREFIX + "FileRead"; public static final String FileWrite = PREFIX + "FileWrite"; public static final String SocketRead = PREFIX + "SocketRead"; diff --git a/test/lib/jdk/test/lib/jfr/GCHelper.java b/test/lib/jdk/test/lib/jfr/GCHelper.java index aee67c6f4add2..07c6c1e1ce550 100644 --- a/test/lib/jdk/test/lib/jfr/GCHelper.java +++ b/test/lib/jdk/test/lib/jfr/GCHelper.java @@ -74,7 +74,6 @@ public class GCHelper { public static final String gcPSMarkSweep = "PSMarkSweep"; public static final String gcParallelOld = "ParallelOld"; public static final String pauseLevelEvent = "GCPhasePauseLevel"; - public static final String gcShenandoah = "Shenandoah"; private static final List g1HeapRegionTypes; private static final List shenandoahHeapRegionStates; @@ -93,22 +92,20 @@ public static boolean isGcEvent(RecordedEvent event) { return false; } - // public static String getEventDesc(RecordedEvent event) { - // final String path = event.getEventType().getName(); - // if (!isGcEvent(event)) { - // return path; - // } - // if (event_garbage_collection.equals(path)) { - // String name = Events.assertField(event, "name").getValue(); - // String cause = Events.assertField(event, "cause").getValue(); - // return String.format("path=%s, gcId=%d, endTime=%d, name=%s, cause=%s, - // startTime=%d", - // path, getGcId(event), event.getEndTime(), name, cause, event.getStartTime()); - // } else { - // return String.format("path=%s, gcId=%d, endTime=%d", path, getGcId(event), - // event.getEndTime()); - // } - // } +// public static String getEventDesc(RecordedEvent event) { +// final String path = event.getEventType().getName(); +// if (!isGcEvent(event)) { +// return path; +// } +// if (event_garbage_collection.equals(path)) { +// String name = Events.assertField(event, "name").getValue(); +// String cause = Events.assertField(event, "cause").getValue(); +// return String.format("path=%s, gcId=%d, endTime=%d, name=%s, cause=%s, startTime=%d", +// path, getGcId(event), event.getEndTime(), name, cause, event.getStartTime()); +// } else { +// return String.format("path=%s, gcId=%d, endTime=%d", path, getGcId(event), event.getEndTime()); +// } +// } public static RecordedEvent getConfigEvent(List events) throws Exception { for (RecordedEvent event : events) { @@ -180,50 +177,40 @@ public static List removeFirstAndLastGC(List event beanCollectorTypes.put("PS MarkSweep", false); beanCollectorTypes.put("MarkSweepCompact", false); - // List of expected collector overrides. "A.B" means that collector A may use - // collector B. + // List of expected collector overrides. "A.B" means that collector A may use collector B. collectorOverrides.add("G1Old.G1Full"); collectorOverrides.add("SerialOld.PSMarkSweep"); - requiredEvents.put(gcG1New, new String[] { event_heap_summary, event_young_garbage_collection }); - requiredEvents.put(gcDefNew, new String[] { event_heap_summary, event_heap_metaspace_summary, - event_phases_pause, event_phases_level_1, event_young_garbage_collection }); - requiredEvents.put(gcParallelScavenge, - new String[] { event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, - event_reference_statistics, event_phases_pause, event_phases_level_1, - event_young_garbage_collection }); - requiredEvents.put(gcG1Old, new String[] { event_heap_summary, event_old_garbage_collection }); - requiredEvents.put(gcG1Full, new String[] { event_heap_summary, event_heap_metaspace_summary, - event_phases_pause, event_phases_level_1, event_old_garbage_collection }); - requiredEvents.put(gcSerialOld, new String[] { event_heap_summary, event_heap_metaspace_summary, - event_phases_pause, event_phases_level_1, event_old_garbage_collection }); - requiredEvents.put(gcParallelOld, - new String[] { event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, - event_reference_statistics, event_phases_pause, event_phases_level_1, - event_old_garbage_collection, event_parold_garbage_collection }); + requiredEvents.put(gcG1New, new String[] {event_heap_summary, event_young_garbage_collection}); + requiredEvents.put(gcDefNew, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_young_garbage_collection}); + requiredEvents.put(gcParallelScavenge, new String[] {event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, event_reference_statistics, event_phases_pause, event_phases_level_1, event_young_garbage_collection}); + requiredEvents.put(gcG1Old, new String[] {event_heap_summary, event_old_garbage_collection}); + requiredEvents.put(gcG1Full, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_old_garbage_collection}); + requiredEvents.put(gcSerialOld, new String[] {event_heap_summary, event_heap_metaspace_summary, event_phases_pause, event_phases_level_1, event_old_garbage_collection}); + requiredEvents.put(gcParallelOld, new String[] {event_heap_summary, event_heap_ps_summary, event_heap_metaspace_summary, event_reference_statistics, event_phases_pause, event_phases_level_1, event_old_garbage_collection, event_parold_garbage_collection}); String[] g1HeapRegionTypeLiterals = new String[] { - "Free", - "Eden", - "Survivor", - "Starts Humongous", - "Continues Humongous", - "Old" - }; + "Free", + "Eden", + "Survivor", + "Starts Humongous", + "Continues Humongous", + "Old" + }; g1HeapRegionTypes = Collections.unmodifiableList(Arrays.asList(g1HeapRegionTypeLiterals)); String[] shenandoahHeapRegionStateLiterals = new String[] { - "Empty Uncommitted", - "Empty Committed", - "Regular", - "Humongous Start", - "Humongous Continuation", - "Humongous Start, Pinned", - "Collection Set", - "Pinned", - "Collection Set, Pinned", - "Trash" + "Empty Uncommitted", + "Empty Committed", + "Regular", + "Humongous Start", + "Humongous Continuation", + "Humongous Start, Pinned", + "Collection Set", + "Pinned", + "Collection Set, Pinned", + "Trash" }; shenandoahHeapRegionStates = Collections.unmodifiableList(Arrays.asList(shenandoahHeapRegionStateLiterals)); @@ -258,10 +245,8 @@ public boolean addEvent(RecordedEvent event) { } boolean isEndEvent = event_garbage_collection.equals(event.getEventType().getName()); if (isEndEvent) { - // Verify that we have not already got a garbage_collection event with this - // gcId. - assertNull(getEndEvent(), - String.format("Multiple %s for gcId %d", event_garbage_collection, getGcId())); + // Verify that we have not already got a garbage_collection event with this gcId. + assertNull(getEndEvent(), String.format("Multiple %s for gcId %d", event_garbage_collection, getGcId())); } events.add(event); return isEndEvent; @@ -354,8 +339,7 @@ public static List createFromEvents(List events) throws openGcIds.pop(); } } - // Verify that all start_garbage_collection events have received a corresponding - // "garbage_collection" event. + // Verify that all start_garbage_collection events have received a corresponding "garbage_collection" event. for (GcBatch batch : batches) { if (batch.getEndEvent() == null) { System.out.println(batch.getLog()); @@ -367,8 +351,7 @@ public static List createFromEvents(List events) throws } /** - * Contains number of collections and sum pause time for young and old - * collections. + * Contains number of collections and sum pause time for young and old collections. */ public static class CollectionSummary { public long collectionCountOld; @@ -408,7 +391,7 @@ public CollectionSummary calcDelta(CollectionSummary prev) { public static CollectionSummary createFromMxBeans() { CollectionSummary summary = new CollectionSummary(); List gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); - for (int c = 0; c < gcBeans.size(); c++) { + for (int c=0; c Date: Fri, 18 Jul 2025 17:58:28 +0000 Subject: [PATCH 18/26] Attempt to fix assert error --- src/hotspot/share/gc/shared/gcTrace.cpp | 1 + .../share/gc/shared/objectCountEventSenderTemplate.hpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 8b8d57bffec78..1b426a59276e4 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -33,6 +33,7 @@ #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/debug.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp index 33fe676638890..c941415c100ed 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -74,10 +74,10 @@ void ObjectCountEventSenderTemplate::send(const KlassInfoEntry* entry, co Klass* klass = entry->klass(); jlong count = entry->count(); julong total_size = entry->words() * BytesPerWord; - + send_event_if_enabled(klass, count, total_size, timestamp); // If sending ObjectCountAfterGCEvent, check if ObjectCount is enabled and send event data to ObjectCount - if (std::is_same::value && ObjectCountEventSender::should_send_event()) { + if (std::is_same::value && ObjectCountEventSender::should_send_event()) { send_event_if_enabled(klass, count, total_size, timestamp); } } From e4747f257970e6cdabcf90322daa8a911dce3835 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 18 Jul 2025 18:43:08 +0000 Subject: [PATCH 19/26] Removed iostream in objectCountEventSenderTemplate --- src/hotspot/share/gc/shared/gcTrace.cpp | 1 - src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 1b426a59276e4..8b8d57bffec78 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -33,7 +33,6 @@ #include "memory/resourceArea.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/debug.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp index c941415c100ed..28a66ea15fcff 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -6,8 +6,6 @@ #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" -#include "iostream" - #if INCLUDE_SERVICES class KlassInfoEntry; @@ -77,6 +75,7 @@ void ObjectCountEventSenderTemplate::send(const KlassInfoEntry* entry, co send_event_if_enabled(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::value && ObjectCountEventSender::should_send_event()) { send_event_if_enabled(klass, count, total_size, timestamp); } From 0a9c09431e1700ea0e07d7fea100b94351f5fe82 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 18 Jul 2025 22:38:08 +0000 Subject: [PATCH 20/26] Add template for the method that reports object count and updated rest of collectors to use this method --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 3 ++- src/hotspot/share/gc/g1/g1FullCollector.cpp | 3 ++- .../share/gc/parallel/psParallelCompact.cpp | 3 ++- src/hotspot/share/gc/serial/serialFullGC.cpp | 3 ++- src/hotspot/share/gc/shared/gcTrace.cpp | 24 +++++++------------ src/hotspot/share/gc/shared/gcTrace.hpp | 3 +++ .../gc/shenandoah/shenandoahConcurrentGC.cpp | 3 ++- test/lib/jdk/test/lib/jfr/GCHelper.java | 1 + 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 6cf5c70f20543..4a70ec628c435 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -49,6 +49,7 @@ #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcVMOperations.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/suspendibleThreadSet.hpp" @@ -1471,7 +1472,7 @@ void G1ConcurrentMark::remark() { { GCTraceTime(Debug, gc, phases) debug("Report Object Count", _gc_timer_cm); G1ObjectCountIsAliveClosure is_alive(_g1h); - _gc_tracer_cm->report_object_count_after_gc(&is_alive, _g1h->workers()); + _gc_tracer_cm->report_object_count(&is_alive, _g1h->workers()); } } else { // We overflowed. Restart concurrent marking. diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 4992df8e214e4..13523608fc234 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -37,6 +37,7 @@ #include "gc/g1/g1RegionMarkStatsCache.inline.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/verifyOption.hpp" @@ -329,7 +330,7 @@ void G1FullCollector::phase1_mark_live_objects() { { GCTraceTime(Debug, gc, phases) debug("Report Object Count", scope()->timer()); - scope()->tracer()->report_object_count_after_gc(&_is_alive, _heap->workers()); + scope()->tracer()->report_object_count(&_is_alive, _heap->workers()); } #if TASKQUEUE_STATS oop_queue_set()->print_and_reset_taskqueue_stats("Oop Queue"); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 50f22a5ef9aef..3b2a1d1064f07 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -53,6 +53,7 @@ #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/isGCActiveMark.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.inline.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" @@ -1373,7 +1374,7 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { { GCTraceTime(Debug, gc, phases) tm("Report Object Count", &_gc_timer); - _gc_tracer.report_object_count_after_gc(is_alive_closure(), &ParallelScavengeHeap::heap()->workers()); + _gc_tracer.report_object_count(is_alive_closure(), &ParallelScavengeHeap::heap()->workers()); } #if TASKQUEUE_STATS ParCompactionManager::print_and_reset_taskqueue_stats(); diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index da5b8ba53a029..28b6d88dd658e 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -49,6 +49,7 @@ #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/modRefBarrierSet.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" @@ -550,7 +551,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) { { GCTraceTime(Debug, gc, phases) tm_m("Report Object Count", gc_timer()); - gc_tracer()->report_object_count_after_gc(&is_alive, nullptr); + gc_tracer()->report_object_count(&is_alive, nullptr); } } diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 8b8d57bffec78..d98bf103f26bb 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -101,35 +101,22 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; +template void GCTracer::report_object_count(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { assert(is_alive_cl != nullptr, "Must supply function to check liveness"); - if (ObjectCountEventSender::should_send_event()) { + 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_sender(cit.size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure 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) { - assert(is_alive_cl != nullptr, "Must supply function to check liveness"); - if (ObjectCountAfterGCEventSender::should_send_event()) { - 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()); - cit.iterate(&event_sender); - } - } -} #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { @@ -203,3 +190,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(BoolObjectClosure*, WorkerThreads*); +template void GCTracer::report_object_count(BoolObjectClosure*, WorkerThreads*); +#endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 2d7366b17e893..cbf79535f7283 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -103,7 +103,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; + + template void report_object_count(BoolObjectClosure* object_filter, WorkerThreads* workers) 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/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index c983c89c5fdfe..c6c8f3992b9ac 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -29,6 +29,7 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -773,7 +774,7 @@ void ShenandoahConcurrentGC::op_final_mark() { } ShenandoahIsAliveClosure is_alive; - heap->tracer()->report_object_count(&is_alive, heap->workers()); + heap->tracer()->report_object_count(&is_alive, heap->workers()); if (!heap->cancelled_gc()) { _mark.finish_mark(); diff --git a/test/lib/jdk/test/lib/jfr/GCHelper.java b/test/lib/jdk/test/lib/jfr/GCHelper.java index 07c6c1e1ce550..4b30e79ba0d43 100644 --- a/test/lib/jdk/test/lib/jfr/GCHelper.java +++ b/test/lib/jdk/test/lib/jfr/GCHelper.java @@ -74,6 +74,7 @@ public class GCHelper { public static final String gcPSMarkSweep = "PSMarkSweep"; public static final String gcParallelOld = "ParallelOld"; public static final String pauseLevelEvent = "GCPhasePauseLevel"; + public static final String gcShenandoah = "Shenandoah"; private static final List g1HeapRegionTypes; private static final List shenandoahHeapRegionStates; From b88dce2802c94e25345c90a9ef4965a44345211a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 21 Jul 2025 16:46:58 +0000 Subject: [PATCH 21/26] Reverting back to old commit --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 3 +-- src/hotspot/share/gc/g1/g1FullCollector.cpp | 3 +-- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 3 +-- src/hotspot/share/gc/serial/serialFullGC.cpp | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 4a70ec628c435..6cf5c70f20543 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -49,7 +49,6 @@ #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcVMOperations.hpp" -#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/suspendibleThreadSet.hpp" @@ -1472,7 +1471,7 @@ void G1ConcurrentMark::remark() { { GCTraceTime(Debug, gc, phases) debug("Report Object Count", _gc_timer_cm); G1ObjectCountIsAliveClosure is_alive(_g1h); - _gc_tracer_cm->report_object_count(&is_alive, _g1h->workers()); + _gc_tracer_cm->report_object_count_after_gc(&is_alive, _g1h->workers()); } } else { // We overflowed. Restart concurrent marking. diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 13523608fc234..4992df8e214e4 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -37,7 +37,6 @@ #include "gc/g1/g1RegionMarkStatsCache.inline.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/verifyOption.hpp" @@ -330,7 +329,7 @@ void G1FullCollector::phase1_mark_live_objects() { { GCTraceTime(Debug, gc, phases) debug("Report Object Count", scope()->timer()); - scope()->tracer()->report_object_count(&_is_alive, _heap->workers()); + scope()->tracer()->report_object_count_after_gc(&_is_alive, _heap->workers()); } #if TASKQUEUE_STATS oop_queue_set()->print_and_reset_taskqueue_stats("Oop Queue"); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 3b2a1d1064f07..50f22a5ef9aef 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -53,7 +53,6 @@ #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gcVMOperations.hpp" #include "gc/shared/isGCActiveMark.hpp" -#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.inline.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" @@ -1374,7 +1373,7 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { { GCTraceTime(Debug, gc, phases) tm("Report Object Count", &_gc_timer); - _gc_tracer.report_object_count(is_alive_closure(), &ParallelScavengeHeap::heap()->workers()); + _gc_tracer.report_object_count_after_gc(is_alive_closure(), &ParallelScavengeHeap::heap()->workers()); } #if TASKQUEUE_STATS ParCompactionManager::print_and_reset_taskqueue_stats(); diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index 28b6d88dd658e..da5b8ba53a029 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -49,7 +49,6 @@ #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/modRefBarrierSet.hpp" -#include "gc/shared/objectCountEventSenderTemplate.hpp" #include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" @@ -551,7 +550,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) { { GCTraceTime(Debug, gc, phases) tm_m("Report Object Count", gc_timer()); - gc_tracer()->report_object_count(&is_alive, nullptr); + gc_tracer()->report_object_count_after_gc(&is_alive, nullptr); } } From 5f912be9a8e837d7c043b3dcd0184678155562f4 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 21 Jul 2025 17:10:23 +0000 Subject: [PATCH 22/26] Uncommented report_object_count_after_gc --- src/hotspot/share/gc/shared/gcTrace.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index d98bf103f26bb..f78bcb417bfa8 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -101,7 +101,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -template +template void GCTracer::report_object_count(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { assert(is_alive_cl != nullptr, "Must supply function to check liveness"); if (Event::should_send_event()) { @@ -117,6 +117,21 @@ void GCTracer::report_object_count(BoolObjectClosure* is_alive_cl, WorkerThreads } } +void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { + assert(is_alive_cl != nullptr, "Must supply function to check liveness"); + if (ObjectCountAfterGCEventSender::should_send_event()) { + 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()); + cit.iterate(&event_sender); + } + } +} + #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { From 08fc38ce626c7864eeb394b4a981ed40dd100e11 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 21 Jul 2025 19:08:08 +0000 Subject: [PATCH 23/26] Added KlassInfoTable to ObjectCount class --- .../shared/objectCountEventSenderTemplate.hpp | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp index 28a66ea15fcff..f331cfa7fb0ba 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -14,13 +14,17 @@ class Klass; template class ObjectCountEventSenderTemplate : public AllStatic { static bool _should_send_requestable_event; + static KlassInfoTable cit; template static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp); public: + static bool check_table_exists(); + 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(); @@ -41,6 +45,24 @@ bool ObjectCountEventSenderTemplate::should_send_event() { template bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; +template +KlassInfoTable ObjectCountEventSenderTemplate::cit(false); + +template +bool ObjectCountEventSenderTemplate::check_table_exists() { + return !cit.allocation_failed(); +} + +template +bool ObjectCountEventSenderTemplate::record_object_instance(oop o) { + if (!check_table_exists()) { + return false; + } + cit.record_instance(o); + return true; +} + + template void ObjectCountEventSenderTemplate::enable_requestable_event() { _should_send_requestable_event = true; From 4c02ed1fd4db670e0030251c7fcef98b90f4db0a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 22 Jul 2025 20:24:27 +0000 Subject: [PATCH 24/26] Restored objectCountEventSender --- .../gc/shared/objectCountEventSender.cpp | 88 +++++++++++++++++++ .../gc/shared/objectCountEventSender.hpp | 59 +++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.cpp create mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.hpp diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp new file mode 100644 index 0000000000000..fdbc307216b89 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#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" +#if INCLUDE_SERVICES + +template +bool ObjectCountEventSender::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || Event::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + +bool ObjectCountEventSender::_should_send_requestable_event = false; + +void ObjectCountEventSender::enable_requestable_event() { + _should_send_requestable_event = true; +} + +void ObjectCountEventSender::disable_requestable_event() { + _should_send_requestable_event = false; +} + +template +void ObjectCountEventSender::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 +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(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::value && ObjectCountEventSender::should_send_event()) { + send_event_if_enabled(klass, count, total_size, timestamp); + } +} + +template bool ObjectCountEventSender::should_send_event(); +template bool ObjectCountEventSender::should_send_event(); + +template void ObjectCountEventSender::send(const KlassInfoEntry*, const Ticks&); +template void ObjectCountEventSender::send(const KlassInfoEntry*, const Ticks&); + +#endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp new file mode 100644 index 0000000000000..b05af2bb8b071 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP + +#include "gc/shared/gcTrace.hpp" +#include "memory/allStatic.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" +#include "utilities/ticks.hpp" + +#if INCLUDE_SERVICES + +class KlassInfoEntry; +class Klass; + +class ObjectCountEventSender : public AllStatic { + static bool _should_send_requestable_event; + + template + 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 + static void send(const KlassInfoEntry* entry, const Ticks& timestamp); + + template + static bool should_send_event(); +}; + + +#endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP From 520f5341da0ac43c8f0e9b4f9deec0c7e5c2218e Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 22 Jul 2025 21:23:39 +0000 Subject: [PATCH 25/26] Efficient implementation of ObjectCountAfterGC --- src/hotspot/share/gc/shared/gcTrace.cpp | 47 ++-- src/hotspot/share/gc/shared/gcTrace.hpp | 6 +- .../shared/objectCountEventSenderTemplate.hpp | 217 ++++++++++-------- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 17 +- .../gc/shenandoah/shenandoahMark.inline.hpp | 4 + .../share/jfr/periodic/jfrPeriodic.cpp | 1 + src/jdk.jfr/share/conf/jfr/profile.jfc | 2 +- 7 files changed, 165 insertions(+), 129 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index f78bcb417bfa8..a5ca715bd40f3 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,7 +27,9 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/objectCountEventSenderTemplate.hpp" +#include "jfr/jfrEvents.hpp" +#include "gc/shared/objectCountClosure.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" @@ -90,7 +92,8 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { - Event::send(entry, _timestamp); + ObjectCountEventSender::send(entry, _timestamp); + // Event::send(entry, _timestamp); } } @@ -101,32 +104,34 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -template -void GCTracer::report_object_count(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { - assert(is_alive_cl != nullptr, "Must supply function to check liveness"); - if (Event::should_send_event()) { - ResourceMark rm; +void GCTracer::report_object_count(KlassInfoTable* cit) { + ObjectCountEventSenderClosure 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_sender(cit.size_of_instances_in_words(), Ticks::now()); - cit.iterate(&event_sender); - } - } + // 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()); + // cit.iterate(&event_sender); + // } + // } } void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { assert(is_alive_cl != nullptr, "Must supply function to check liveness"); - if (ObjectCountAfterGCEventSender::should_send_event()) { + if (ObjectCountEventSender::should_send_event()) { 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 event_sender(cit.size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); cit.iterate(&event_sender); } } @@ -206,7 +211,7 @@ void OldGCTracer::report_concurrent_mode_failure() { send_concurrent_mode_failure_event(); } -#if INCLUDE_SERVICES -template void GCTracer::report_object_count(BoolObjectClosure*, WorkerThreads*); -template void GCTracer::report_object_count(BoolObjectClosure*, WorkerThreads*); -#endif // INCLUDE_SERVICES +// #if INCLUDE_SERVICES +// template void GCTracer::report_object_count(KlassInfoTable*); +// template void GCTracer::report_object_count(KlassInfoTable*); +// #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index cbf79535f7283..d257f54ef36f1 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -35,6 +35,7 @@ #include "memory/referenceType.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" +#include "memory/heapInspection.hpp" class GCHeapSummary; class MetaspaceChunkFreeListSummary; @@ -104,10 +105,9 @@ class GCTracer { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; - template - void report_object_count(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; + void report_object_count(KlassInfoTable* cit) NOT_SERVICES_RETURN; - void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) 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: diff --git a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp index f331cfa7fb0ba..136977023f124 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp @@ -1,107 +1,122 @@ -#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP -#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP +// #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 +// #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; +// class KlassInfoEntry; +// class Klass; -template -class ObjectCountEventSenderTemplate : public AllStatic { - static bool _should_send_requestable_event; - static KlassInfoTable cit; +// template +// class ObjectCountEventSenderTemplate : public AllStatic { +// static bool _should_send_requestable_event; +// static KlassInfoTable cit; - template - static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp); +// template +// 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(); - public: - static bool check_table_exists(); - 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 ObjectCountEventSender; -typedef ObjectCountEventSenderTemplate ObjectCountAfterGCEventSender; - -template -bool ObjectCountEventSenderTemplate::should_send_event() { -#if INCLUDE_JFR - return _should_send_requestable_event || Event::is_enabled(); -#else - return false; -#endif // INCLUDE_JFR -} - -template -bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; - -template -KlassInfoTable ObjectCountEventSenderTemplate::cit(false); - -template -bool ObjectCountEventSenderTemplate::check_table_exists() { - return !cit.allocation_failed(); -} - -template -bool ObjectCountEventSenderTemplate::record_object_instance(oop o) { - if (!check_table_exists()) { - return false; - } - cit.record_instance(o); - return true; -} - - -template -void ObjectCountEventSenderTemplate::enable_requestable_event() { - _should_send_requestable_event = true; -} - - -template -void ObjectCountEventSenderTemplate::disable_requestable_event() { - _should_send_requestable_event = false; -} - -template -template -void ObjectCountEventSenderTemplate::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 -void ObjectCountEventSenderTemplate::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(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::value && ObjectCountEventSender::should_send_event()) { - send_event_if_enabled(klass, count, total_size, timestamp); - } -} -#endif // INCLUDE_SERVICES - -#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP +// 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 ObjectCountEventSender; +// typedef ObjectCountEventSenderTemplate ObjectCountAfterGCEventSender; + +// template +// bool ObjectCountEventSenderTemplate::should_send_event() { +// #if INCLUDE_JFR +// return _should_send_requestable_event || Event::is_enabled(); +// #else +// return false; +// #endif // INCLUDE_JFR +// } + +// template +// bool ObjectCountEventSenderTemplate::_should_send_requestable_event = false; + +// template +// KlassInfoTable ObjectCountEventSenderTemplate::cit(false); + +// template +// void ObjectCountEventSenderTemplate::reset_table() { +// cit.~KlassInfoTable(); +// ::new((void*)&cit) KlassInfoTable(false); +// } + + +// template +// bool ObjectCountEventSenderTemplate::check_table_exists() { +// return !cit.allocation_failed(); +// } + +// template +// bool ObjectCountEventSenderTemplate::record_object_instance(oop o) { +// if (!check_table_exists()) { +// return false; +// } +// cit.record_instance(o); +// return true; +// } + +// template +// KlassInfoTable* ObjectCountEventSenderTemplate::get_table() { +// return &cit; +// } + + +// template +// void ObjectCountEventSenderTemplate::enable_requestable_event() { +// _should_send_requestable_event = true; +// } + + +// template +// void ObjectCountEventSenderTemplate::disable_requestable_event() { +// _should_send_requestable_event = false; +// } + +// template +// template +// void ObjectCountEventSenderTemplate::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 +// void ObjectCountEventSenderTemplate::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(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::value && ObjectCountEventSender::should_send_event()) { +// send_event_if_enabled(klass, count, total_size, timestamp); +// } +// } +// #endif // INCLUDE_SERVICES + +// #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index c6c8f3992b9ac..578f1b67a4dbe 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -29,7 +29,8 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/objectCountEventSenderTemplate.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" @@ -773,8 +774,18 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->verifier()->verify_roots_no_forwarded(); } - ShenandoahIsAliveClosure is_alive; - heap->tracer()->report_object_count(&is_alive, heap->workers()); + // 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(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 2dc0813e51354..5e3ee66a98d92 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -47,6 +47,7 @@ #include "runtime/prefetch.inline.hpp" #include "utilities/devirtualizer.inline.hpp" #include "utilities/powerOfTwo.hpp" +#include "gc/shared/objectCountClosure.hpp" template void ShenandoahMark::dedup_string(oop obj, StringDedup::Requests* const req) { @@ -365,6 +366,9 @@ inline void ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, marked = mark_context->mark_strong(obj, /* was_upgraded = */ skip_live); } if (marked) { + if (ObjectCountClosure::should_send_event()) { + ObjectCountClosure::record_object(obj); + } bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); assert(pushed, "overflow queue should always succeed pushing"); } diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index c478a0a18432a..62b2b4dff47cc 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -33,6 +33,7 @@ #include "gc/shared/gcConfiguration.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/gcVMOperations.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/objectCountEventSenderTemplate.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index 5ffdc8d9e4dbf..d7b7b6e1921ad 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -360,7 +360,7 @@ - false + true From b3b5706c68c6c8dd39eb05cf5280a2ff53ae00db Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 22 Jul 2025 21:32:58 +0000 Subject: [PATCH 26/26] New closure for object counting --- .../share/gc/shared/objectCountClosure.cpp | 35 +++++++++++++++++++ .../share/gc/shared/objectCountClosure.hpp | 24 +++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/hotspot/share/gc/shared/objectCountClosure.cpp create mode 100644 src/hotspot/share/gc/shared/objectCountClosure.hpp diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp new file mode 100644 index 0000000000000..68dd721056f50 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -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; +} diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp new file mode 100644 index 0000000000000..684d8db45c7c5 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -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