From 469fd32fc08581ec95f151490d84693b29824233 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 9 Jul 2025 18:48:27 +0000 Subject: [PATCH 001/104] Testing ObjectCount event with Shenandoah --- .../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 19:03:08 +0000 Subject: [PATCH 002/104] Revert "8358533: Improve performance of java.io.Reader.readAllLines" This reverts commit 6e203384f8777fc55081065b128bd2b0ba074729. --- .../share/classes/java/io/Reader.java | 73 +++--------------- test/jdk/java/io/Reader/ReadAll.java | 75 +------------------ .../bench/java/io/ReaderReadAllLines.java | 66 ---------------- 3 files changed, 16 insertions(+), 198 deletions(-) delete mode 100644 test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java diff --git a/src/java.base/share/classes/java/io/Reader.java b/src/java.base/share/classes/java/io/Reader.java index 9656d14002337..af5ac9f68ec7c 100644 --- a/src/java.base/share/classes/java/io/Reader.java +++ b/src/java.base/share/classes/java/io/Reader.java @@ -27,11 +27,8 @@ import java.nio.CharBuffer; import java.nio.ReadOnlyBufferException; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; -import jdk.internal.util.ArraysSupport; /** * Abstract class for reading character streams. The only methods that a @@ -400,6 +397,16 @@ public int read(char[] cbuf) throws IOException { */ public abstract int read(char[] cbuf, int off, int len) throws IOException; + private String readAllCharsAsString() throws IOException { + StringBuilder result = new StringBuilder(); + char[] cbuf = new char[TRANSFER_BUFFER_SIZE]; + int nread; + while ((nread = read(cbuf, 0, cbuf.length)) != -1) { + result.append(cbuf, 0, nread); + } + return result.toString(); + } + /** * Reads all remaining characters as lines of text. This method blocks until * all remaining characters have been read and end of stream is detected, @@ -450,57 +457,7 @@ public int read(char[] cbuf) throws IOException { * @since 25 */ public List readAllLines() throws IOException { - List lines = new ArrayList<>(); - char[] cb = new char[1024]; - - int start = 0; - int pos = 0; - int limit = 0; - boolean skipLF = false; - int n; - while ((n = read(cb, pos, cb.length - pos)) != -1) { - limit = pos + n; - while (pos < limit) { - if (skipLF) { - if (cb[pos] == '\n') { - pos++; - start++; - } - skipLF = false; - } - while (pos < limit) { - char c = cb[pos++]; - if (c == '\n' || c == '\r') { - lines.add(new String(cb, start, pos - 1 - start)); - skipLF = (c == '\r'); - start = pos; - break; - } - } - if (pos == limit) { - int len = limit - start; - if (len >= cb.length/2) { - // allocate larger buffer and copy chars to beginning - int newLength = ArraysSupport.newLength(cb.length, - TRANSFER_BUFFER_SIZE, cb.length); - char[] tmp = new char[newLength]; - System.arraycopy(cb, start, tmp, 0, len); - cb = tmp; - } else if (start != 0 && len != 0) { - // move fragment to beginning of buffer - System.arraycopy(cb, start, cb, 0, len); - } - pos = limit = len; - start = 0; - break; - } - } - } - // add a string if EOS terminates the last line - if (limit > start) - lines.add(new String(cb, start, limit - start)); - - return Collections.unmodifiableList(lines); + return readAllCharsAsString().lines().toList(); } /** @@ -542,13 +499,7 @@ public List readAllLines() throws IOException { * @since 25 */ public String readAllAsString() throws IOException { - StringBuilder result = new StringBuilder(); - char[] cbuf = new char[TRANSFER_BUFFER_SIZE]; - int nread; - while ((nread = read(cbuf, 0, cbuf.length)) != -1) { - result.append(cbuf, 0, nread); - } - return result.toString(); + return readAllCharsAsString(); } /** Maximum skip-buffer size */ diff --git a/test/jdk/java/io/Reader/ReadAll.java b/test/jdk/java/io/Reader/ReadAll.java index fbe1d5a6431a0..72fcf459eca77 100644 --- a/test/jdk/java/io/Reader/ReadAll.java +++ b/test/jdk/java/io/Reader/ReadAll.java @@ -66,55 +66,12 @@ public static void setup() throws IOException { int size = rnd.nextInt(2, 16386); int plen = PHRASE.length(); - StringBuilder sb = new StringBuilder(plen); - List strings = new ArrayList<>(size); + List strings = new ArrayList(size); while (strings.size() < size) { int fromIndex = rnd.nextInt(0, plen / 2); int toIndex = rnd.nextInt(fromIndex, plen); - String s = PHRASE.substring(fromIndex, toIndex); - sb.append(s); - int bound = toIndex - fromIndex; - if (bound > 0) { - int offset = bound/2; - int n = rnd.nextInt(0, bound); - for (int i = 0; i < n; i++) { - String f = null; - switch (rnd.nextInt(7)) { - case 0 -> f = ""; - case 1 -> f = "\r"; - case 2 -> f = "\n"; - case 3 -> f = "\r\n"; - case 4 -> f = "\r\r"; - case 5 -> f = "\n\n"; - case 6 -> f = " "; - } - sb.insert(offset, f); - } - } - strings.add(sb.toString()); - sb.setLength(0); + strings.add(PHRASE.substring(fromIndex, toIndex)); } - - String p4096 = PHRASE.repeat((4096 + plen - 1)/plen); - String p8192 = PHRASE.repeat((8192 + plen - 1)/plen); - String p16384 = PHRASE.repeat((16384 + plen - 1)/plen); - - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 32; j++) { - switch (rnd.nextInt(8)) { - case 0 -> sb.append(""); - case 1 -> sb.append(" "); - case 2 -> sb.append("\n"); - case 3 -> sb.append(PHRASE); - case 5 -> sb.append(p4096); - case 6 -> sb.append(p8192); - case 7 -> sb.append(p16384); - } - } - strings.add(sb.toString()); - sb.setLength(0); - } - Files.write(path, strings); System.out.println(strings.size() + " lines written"); } @@ -128,7 +85,6 @@ public static void cleanup() throws IOException { @Test public void readAllLines() throws IOException { // Reader implementation - System.out.println("Reader implementation"); List lines; try (FileReader fr = new FileReader(file)) { lines = fr.readAllLines(); @@ -136,21 +92,9 @@ public void readAllLines() throws IOException { System.out.println(lines.size() + " lines read"); List linesExpected = Files.readAllLines(path); - int count = linesExpected.size(); - if (lines.size() != count) - throw new RuntimeException("Size mismatch: " + lines.size() + " != " + count); - for (int i = 0; i < count; i++) { - String expected = linesExpected.get(i); - String actual = lines.get(i); - if (!actual.equals(expected)) { - String msg = String.format("%d: \"%s\" != \"%s\"", - i, actual, expected); - throw new RuntimeException(msg); - } - } + assertEquals(linesExpected, lines); // Reader.of implementation - System.out.println("Reader.of implementation"); String stringExpected = Files.readString(path); int n = rnd.nextInt(stringExpected.length()/2); String substringExpected = stringExpected.substring(n); @@ -159,18 +103,7 @@ public void readAllLines() throws IOException { r.skip(n); lines = r.readAllLines(); } - count = linesExpected.size(); - if (lines.size() != count) - throw new RuntimeException("Size mismatch: " + lines.size() + " != " + count); - for (int i = 0; i < count; i++) { - String expected = linesExpected.get(i); - String actual = lines.get(i); - if (!actual.equals(expected)) { - String msg = String.format("%d: \"%s\" != \"%s\"", - i, actual, expected); - throw new RuntimeException(msg); - } - } + assertEquals(linesExpected, lines); } @Test diff --git a/test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java b/test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java deleted file mode 100644 index a3663e083ec9b..0000000000000 --- a/test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 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. - */ -package org.openjdk.bench.java.io; - -import java.io.CharArrayReader; -import java.io.IOException; -import java.io.Reader; -import java.util.List; -import java.util.Random; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; - -@State(Scope.Benchmark) -public class ReaderReadAllLines { - - private char[] chars = null; - - @Setup - public void setup() throws IOException { - final int len = 128_000; - chars = new char[len]; - Random rnd = new Random(System.nanoTime()); - int off = 0; - while (off < len) { - int lineLen = 40 + rnd.nextInt(8192); - if (lineLen > len - off) { - off = len; - } else { - chars[off + lineLen] = '\n'; - off += lineLen; - } - } - } - - @Benchmark - public List readAllLines() throws IOException { - List lines; - try (Reader reader = new CharArrayReader(chars)) { - lines = reader.readAllLines(); - } - return lines; - } -} From 3da9f8936750291fc59346a3c89a3dd76c8346bc Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 9 Jul 2025 19:13:19 +0000 Subject: [PATCH 003/104] 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 004/104] 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 005/104] 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 006/104] 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 007/104] 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 008/104] 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 009/104] 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 010/104] 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 011/104] 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 012/104] 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 013/104] 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 014/104] 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 015/104] 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 016/104] 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 017/104] 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 018/104] 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 019/104] 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 020/104] 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 021/104] 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 022/104] 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 023/104] 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 024/104] 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 025/104] 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 026/104] 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 027/104] 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 028/104] 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 From 5f77cebc250ad36808e53ad2c1695cad394ea4de Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 22 Jul 2025 15:35:14 -0700 Subject: [PATCH 029/104] Delete src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp --- .../shared/objectCountEventSenderTemplate.hpp | 122 ------------------ 1 file changed, 122 deletions(-) delete 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 deleted file mode 100644 index 136977023f124..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountEventSenderTemplate.hpp +++ /dev/null @@ -1,122 +0,0 @@ -// #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP -// #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDERTEMPLATE_HPP - -// #include "gc/shared/gcId.hpp" -// #include "jfr/jfrEvents.hpp" -// #include "memory/heapInspection.hpp" -// #include "utilities/macros.hpp" -// #include "utilities/ticks.hpp" -// #if INCLUDE_SERVICES - -// class KlassInfoEntry; -// class Klass; - -// template -// 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 KlassInfoTable* get_table(); -// static void reset_table(); - - -// 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 From 5466e0e66eb2b1d624f0cdc123066ed5d9ad713c Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 22 Jul 2025 23:51:24 +0000 Subject: [PATCH 030/104] Atomic operations implemented in record_instance and merge_entry --- src/hotspot/share/gc/shared/gcTrace.cpp | 16 ---------------- src/hotspot/share/jfr/periodic/jfrPeriodic.cpp | 1 - src/hotspot/share/memory/heapInspection.cpp | 14 ++++++++------ src/hotspot/share/memory/heapInspection.hpp | 4 ++++ 4 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index a5ca715bd40f3..146e572a83a1a 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -108,17 +108,6 @@ 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); - // } - // } } void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { @@ -210,8 +199,3 @@ 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(KlassInfoTable*); -// template void GCTracer::report_object_count(KlassInfoTable*); -// #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 62b2b4dff47cc..0be1c32728c08 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -34,7 +34,6 @@ #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" diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 867ccc6106d8e..61bdc2b17ce70 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -217,9 +217,10 @@ bool KlassInfoTable::record_instance(const oop obj) { // elt may be null if it's a new klass for which we // could not allocate space for a new entry in the hashtable. if (elt != nullptr) { - elt->set_count(elt->count() + 1); - elt->set_words(elt->words() + obj->size()); - _size_of_instances_in_words += obj->size(); + elt->atomic_inc_count(); + size_t obj_size = obj->size(); + elt->atomic_add_words(obj_size); + Atomic::add(&_size_of_instances_in_words, obj_size); return true; } else { return false; @@ -245,9 +246,10 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { // elt may be null if it's a new klass for which we // could not allocate space for a new entry in the hashtable. if (elt != nullptr) { - elt->set_count(elt->count() + cie->count()); - elt->set_words(elt->words() + cie->words()); - _size_of_instances_in_words += cie->words(); + elt->atomic_add_count(cie->count()); + size_t words_to_add = cie->words(); + elt->atomic_add_words(words_to_add); + Atomic::add(&_size_of_instances_in_words, words_to_add); return true; } return false; diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index ca9a46c9140bd..53f85df247bd1 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -30,6 +30,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" #include "oops/annotations.hpp" +#include "runtime/atomic.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; @@ -71,8 +72,11 @@ class KlassInfoEntry: public CHeapObj { Klass* klass() const { return _klass; } uint64_t count() const { return _instance_count; } void set_count(uint64_t ct) { _instance_count = ct; } + void atomic_inc_count() { Atomic::inc(&_instance_count); } + void atomic_add_count(uint64_t add) { Atomic::add(&_instance_count, add); } size_t words() const { return _instance_words; } void set_words(size_t wds) { _instance_words = wds; } + void atomic_add_words(size_t add) { Atomic::add(&_instance_words, add); } void set_index(int64_t index) { _index = index; } int64_t index() const { return _index; } GrowableArray* subclasses() const { return _subclasses; } From 6c6e9665cd4018f9e3e55a5c6137ab54ce040729 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 17:24:26 +0000 Subject: [PATCH 031/104] Included objectCountEventSender.hpp in objectCountClosure.cpp --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 68dd721056f50..3cfebc15da601 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,5 +1,6 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/objectCountClosure.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" From 57d4ea0363312884a416410a501d0a859263db4d Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 21:42:54 +0000 Subject: [PATCH 032/104] Added clearing entries method for KlassInfoTable --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 6 +++--- src/hotspot/share/memory/heapInspection.cpp | 10 ++++++++++ src/hotspot/share/memory/heapInspection.hpp | 3 ++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 3cfebc15da601..cedaecda43449 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -15,9 +15,9 @@ void ObjectCountClosure::reset_table() { if (!check_table_exists()) { return; } - cit.~KlassInfoTable(); - ::new((void*)&cit) KlassInfoTable(false); -} + cit.clear_entries(); + } + bool ObjectCountClosure::check_table_exists() { return !cit.allocation_failed(); diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 61bdc2b17ce70..6d7103b9173c9 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -267,6 +267,16 @@ class KlassInfoTableMergeClosure : public KlassInfoClosure { bool success() { return _success; } }; +void KlassInfoTable::clear_entries() { + if (_buckets != nullptr) { + for (int index = 0; index < _num_buckets; index++) { + _buckets[index].empty(); + _buckets[index].initialize(); + } + _size_of_instances_in_words = 0; + } +} + // merge from table bool KlassInfoTable::merge(KlassInfoTable* table) { KlassInfoTableMergeClosure closure(this); diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 53f85df247bd1..8cc017c464480 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -130,7 +130,8 @@ class KlassInfoTable: public StackObj { size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); - + // Clears entries in the table + void clear_entries(); friend class KlassInfoHisto; friend class KlassHierarchy; }; From 1c371b26d6fca5dbb42c63c9fefae542f1ed6740 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 22:18:56 +0000 Subject: [PATCH 033/104] Removed inheritance from objectCountClosure --- src/hotspot/share/gc/shared/objectCountClosure.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 684d8db45c7c5..657da9bfa5fe2 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -11,7 +11,7 @@ class KlassInfoEntry; class Klass; -class ObjectCountClosure : public ObjectCountEventSender { +class ObjectCountClosure : public AllStatic { static KlassInfoTable cit; public: @@ -19,6 +19,11 @@ class ObjectCountClosure : public ObjectCountEventSender { static bool record_object(oop o); static KlassInfoTable* get_table(); static void reset_table(); + + template + static bool should_send_event() { + return ObjectCountEventSender::should_send_event(); + } }; #endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP From b1d8145f92e649b728d0b9a38996b70d16d4df2c Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 22:46:35 +0000 Subject: [PATCH 034/104] Templatized should_send_event in ObjectCountClosure --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 9 +++++++++ src/hotspot/share/gc/shared/objectCountClosure.hpp | 4 +--- .../share/gc/shenandoah/shenandoahMark.inline.hpp | 7 ++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index cedaecda43449..c5db989af37c8 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -34,3 +34,12 @@ bool ObjectCountClosure::record_object(oop o) { KlassInfoTable* ObjectCountClosure::get_table() { return check_table_exists() ? &cit : nullptr; } + +template +bool ObjectCountClosure::should_send_event() { + return ObjectCountEventSender::should_send_event(); +} + +template bool ObjectCountClosure::should_send_event(); +template bool ObjectCountClosure::should_send_event(); + diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 657da9bfa5fe2..0d0a50a624cce 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -21,9 +21,7 @@ class ObjectCountClosure : public AllStatic { static void reset_table(); template - static bool should_send_event() { - return ObjectCountEventSender::should_send_event(); - } + static bool should_send_event(); }; #endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 5e3ee66a98d92..718c293923f9c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -366,11 +366,12 @@ 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"); + bool should_record = ObjectCountClosure::should_send_event(); + if (should_record) { + ObjectCountClosure::record_object(obj); + } } } From 24523e778eb8b43b9c4060f0f17d3c1b40a1da61 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 23:02:35 +0000 Subject: [PATCH 035/104] Added include services gaurd to should_send_event() --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index c5db989af37c8..ebf69e94644f0 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -9,6 +9,7 @@ class KlassInfoEntry; class Klass; + KlassInfoTable ObjectCountClosure::cit(false); void ObjectCountClosure::reset_table() { @@ -35,6 +36,8 @@ KlassInfoTable* ObjectCountClosure::get_table() { return check_table_exists() ? &cit : nullptr; } + +#if INCLUDE_SERVICES template bool ObjectCountClosure::should_send_event() { return ObjectCountEventSender::should_send_event(); @@ -42,4 +45,4 @@ bool ObjectCountClosure::should_send_event() { template bool ObjectCountClosure::should_send_event(); template bool ObjectCountClosure::should_send_event(); - +#endif // INCLUDE_SERVICES From dd3cd66e504cd16cbd08f309748d09fe3d48f8f3 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 23:41:30 +0000 Subject: [PATCH 036/104] Attempt to fix incomplete type error --- .../share/gc/shared/objectCountClosure.cpp | 16 ++++++++-------- .../share/gc/shared/objectCountClosure.hpp | 9 +++++++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index ebf69e94644f0..8b8377156d6bd 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -10,33 +10,33 @@ class KlassInfoEntry; class Klass; -KlassInfoTable ObjectCountClosure::cit(false); +static KlassInfoTable _static_table(false); +KlassInfoTable* ObjectCountClosure::cit = &_static_table; void ObjectCountClosure::reset_table() { if (!check_table_exists()) { return; } - cit.clear_entries(); - } - + cit->clear_entries(); +} bool ObjectCountClosure::check_table_exists() { - return !cit.allocation_failed(); + return cit != nullptr && !cit->allocation_failed(); } bool ObjectCountClosure::record_object(oop o) { if (!check_table_exists()) { return false; } - cit.record_instance(o); - return true; + return cit->record_instance(o); } KlassInfoTable* ObjectCountClosure::get_table() { - return check_table_exists() ? &cit : nullptr; + return check_table_exists() ? cit : nullptr; } + #if INCLUDE_SERVICES template bool ObjectCountClosure::should_send_event() { diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 0d0a50a624cce..ef7f3b495b3f6 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -2,19 +2,23 @@ #define SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP #include "gc/shared/gcId.hpp" +#include "memory/allocation.hpp" +#include "memory/heapInspection.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; +#if INCLUDE_SERVICES class ObjectCountClosure : public AllStatic { - static KlassInfoTable cit; + static KlassInfoTable* cit; + // static KlassInfoTable cit; public: + static bool check_table_exists(); static bool record_object(oop o); static KlassInfoTable* get_table(); @@ -23,5 +27,6 @@ class ObjectCountClosure : public AllStatic { template static bool should_send_event(); }; +#endif // INCLUDE_SERVICES #endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP From 69f081364b2c715c56f46658dda64b49fbf45f69 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 23 Jul 2025 23:54:21 +0000 Subject: [PATCH 037/104] Trying to fix forward declaration of 'class Mutex' error --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 + src/hotspot/share/gc/shared/objectCountClosure.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 8b8377156d6bd..0e39e361081b6 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,4 +1,5 @@ #include "gc/shared/gcId.hpp" +#include "runtime/mutex.hpp" #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index ef7f3b495b3f6..3dee5d6c91eff 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -3,6 +3,7 @@ #include "gc/shared/gcId.hpp" #include "memory/allocation.hpp" +#include "runtime/mutex.hpp" #include "memory/heapInspection.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" From eff8b16021d81d02f765b974cf25d2f9c5a1085d Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 17:18:45 +0000 Subject: [PATCH 038/104] Fixed assert error in debug build --- .../share/gc/shared/objectCountClosure.cpp | 15 ++++++++------- .../share/gc/shared/objectCountClosure.hpp | 8 +------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 0e39e361081b6..4c2e0c507a1b8 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,5 +1,4 @@ #include "gc/shared/gcId.hpp" -#include "runtime/mutex.hpp" #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" @@ -10,19 +9,22 @@ class KlassInfoEntry; class Klass; - -static KlassInfoTable _static_table(false); -KlassInfoTable* ObjectCountClosure::cit = &_static_table; +KlassInfoTable* ObjectCountClosure::cit = nullptr; void ObjectCountClosure::reset_table() { if (!check_table_exists()) { return; } cit->clear_entries(); -} + } + bool ObjectCountClosure::check_table_exists() { - return cit != nullptr && !cit->allocation_failed(); + if (cit == nullptr && Universe::is_fully_initialized()) { + static KlassInfoTable temp_table(false); + cit = &temp_table; + } + return !cit->allocation_failed(); } bool ObjectCountClosure::record_object(oop o) { @@ -37,7 +39,6 @@ KlassInfoTable* ObjectCountClosure::get_table() { } - #if INCLUDE_SERVICES template bool ObjectCountClosure::should_send_event() { diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 3dee5d6c91eff..0b4455a34580c 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -2,24 +2,19 @@ #define SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP #include "gc/shared/gcId.hpp" -#include "memory/allocation.hpp" -#include "runtime/mutex.hpp" -#include "memory/heapInspection.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; -#if INCLUDE_SERVICES class ObjectCountClosure : public AllStatic { static KlassInfoTable* cit; - // static KlassInfoTable cit; public: - static bool check_table_exists(); static bool record_object(oop o); static KlassInfoTable* get_table(); @@ -28,6 +23,5 @@ class ObjectCountClosure : public AllStatic { template static bool should_send_event(); }; -#endif // INCLUDE_SERVICES #endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP From 5bf562b7171a65b66dc0b6890e25ba755126a6ba Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 17:46:56 +0000 Subject: [PATCH 039/104] Attempt to remove to unnecessary include for header files --- src/hotspot/share/gc/shared/gcTrace.hpp | 5 ++--- src/hotspot/share/gc/shared/objectCountClosure.cpp | 3 +-- src/hotspot/share/gc/shared/objectCountEventSender.hpp | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index d257f54ef36f1..562c81b0684ee 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -104,10 +104,9 @@ 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; - + // Sends event data to the ObjectCountAfterGC event void report_object_count(KlassInfoTable* cit) NOT_SERVICES_RETURN; - - void report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) NOT_SERVICES_RETURN; + void report_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; protected: diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 4c2e0c507a1b8..bf2a372a2a55c 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -3,11 +3,10 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" +#include "memory/universe.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" -class KlassInfoEntry; -class Klass; KlassInfoTable* ObjectCountClosure::cit = nullptr; diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index b05af2bb8b071..2a3208ef2b375 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -25,7 +25,6 @@ #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" From f3957f0313edf779c164e99beb5d9b711c21fc28 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 17:55:37 +0000 Subject: [PATCH 040/104] Removed memory/heapInspection.hpp --- src/hotspot/share/gc/shared/objectCountClosure.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 0b4455a34580c..57849c18e55c7 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -4,7 +4,6 @@ #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" From 9ab1d45e8ccd89149d47dd50dae1ff6fb08bec0a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 18:15:37 +0000 Subject: [PATCH 041/104] Changed the report_object_count function to call the get_table method in ObjectCountClosure --- src/hotspot/share/gc/shared/gcTrace.cpp | 7 ++++++- src/hotspot/share/gc/shared/gcTrace.hpp | 2 +- src/hotspot/share/gc/shared/objectCountClosure.hpp | 2 ++ src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 5 +---- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 146e572a83a1a..2ccbb4e5e496c 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -104,7 +104,12 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -void GCTracer::report_object_count(KlassInfoTable* cit) { +void GCTracer::report_object_count() { + KlassInfoTable* cit = ObjectCountClosure::get_table(); + if (cit == nullptr) { + return; + } + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); cit->iterate(&event_sender); ObjectCountClosure::reset_table(); diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 562c81b0684ee..327529a7b909e 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -105,7 +105,7 @@ class GCTracer { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; // Sends event data to the ObjectCountAfterGC event - void report_object_count(KlassInfoTable* cit) NOT_SERVICES_RETURN; + void report_object_count() NOT_SERVICES_RETURN; void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; void report_cpu_time_event(double user_time, double system_time, double real_time) const; diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 57849c18e55c7..592dcd101e2df 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -4,6 +4,8 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" +#include "memory/allStatic.hpp" +#include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 578f1b67a4dbe..c53ae12da24f1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -29,8 +29,6 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/objectCountEventSender.hpp" -#include "gc/shared/objectCountClosure.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -776,8 +774,7 @@ void ShenandoahConcurrentGC::op_final_mark() { // Efficient implementation: { - KlassInfoTable* cit = ObjectCountClosure::get_table(); - heap->tracer()->report_object_count(cit); + heap->tracer()->report_object_count(); } // Naive implementation: From 0d5b154c686d6e16f00d793e5dc4678cd16ba467 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 18:35:23 +0000 Subject: [PATCH 042/104] Trying to fix debug build errors --- src/hotspot/share/gc/shared/gcTrace.hpp | 1 - src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 327529a7b909e..72b6300fb16f1 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -35,7 +35,6 @@ #include "memory/referenceType.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" -#include "memory/heapInspection.hpp" class GCHeapSummary; class MetaspaceChunkFreeListSummary; diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index bf2a372a2a55c..254f0ca33a705 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,4 +1,3 @@ -#include "gc/shared/gcId.hpp" #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" From 831995561fb72c691a6e914b60250252efa32875 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 18:49:55 +0000 Subject: [PATCH 043/104] Trying to fix incomplete type error for 'Mutex' --- src/hotspot/share/gc/shared/objectCountEventSender.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index fdbc307216b89..7a4a9e10d6713 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -26,6 +26,7 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" +#include "runtime/mutex.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" From 046be807cc3c18bfded0c0eda36ed2dad27e3e12 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 18:56:00 +0000 Subject: [PATCH 044/104] Included runtime/mutex in object count closure files --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 - src/hotspot/share/gc/shared/objectCountClosure.hpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 254f0ca33a705..e2ad849e4c53a 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,7 +1,6 @@ #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" -#include "memory/heapInspection.hpp" #include "memory/universe.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 592dcd101e2df..5d8fce77d4f90 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -5,6 +5,7 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/allStatic.hpp" +#include "runtime/mutex.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" From 016196b6ddf356495fe8b21393b78901825f8fe6 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 19:07:36 +0000 Subject: [PATCH 045/104] Trying to fix build error --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index e2ad849e4c53a..254f0ca33a705 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,6 +1,7 @@ #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" #include "memory/universe.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" From 35043ee2f2acfc1c469ece80cabd50750eef20a2 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 19:43:31 +0000 Subject: [PATCH 046/104] Trying to fix forward declaration of 'class KlassInfoTable' --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 254f0ca33a705..d65697af4ff9b 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,7 +1,7 @@ +#include "memory/heapInspection.hpp" #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" -#include "memory/heapInspection.hpp" #include "memory/universe.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" From 3b3ed70a92c08a270e1456ebe49861ad727f289d Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 19:54:10 +0000 Subject: [PATCH 047/104] Added runtime/mutex to objectCountClosure --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index d65697af4ff9b..7162852781766 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,3 +1,4 @@ +#include "runtime/mutex.hpp" #include "memory/heapInspection.hpp" #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" From fd0418cd5fb3acccebca7270f52d68532848358f Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 20:00:26 +0000 Subject: [PATCH 048/104] trying to fix debug errors --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 7162852781766..8d07e477adc54 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -1,9 +1,11 @@ -#include "runtime/mutex.hpp" -#include "memory/heapInspection.hpp" + #include "gc/shared/objectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" #include "memory/universe.hpp" +#include "runtime/os.hpp" +#include "runtime/mutex.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" From 97028a79b31390f9d3020c33555f1a734b4caeab Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 20:10:13 +0000 Subject: [PATCH 049/104] Added include services to objectCountClosure.cpp --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 8d07e477adc54..b03b1d07c2b1d 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -4,11 +4,11 @@ #include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" #include "memory/universe.hpp" -#include "runtime/os.hpp" #include "runtime/mutex.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" +#if INCLUDE_SERVICES KlassInfoTable* ObjectCountClosure::cit = nullptr; @@ -40,7 +40,6 @@ KlassInfoTable* ObjectCountClosure::get_table() { } -#if INCLUDE_SERVICES template bool ObjectCountClosure::should_send_event() { return ObjectCountEventSender::should_send_event(); From 5de6cc913a7c2a8ac4e7b38398ed3a2015bc7054 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 24 Jul 2025 20:35:29 +0000 Subject: [PATCH 050/104] Added extra check to see if ObjectCountAfterGC is enabled in report_object_count() --- src/hotspot/share/gc/shared/gcTrace.cpp | 3 +-- src/hotspot/share/gc/shared/objectCountClosure.cpp | 1 + src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 7 ------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 2ccbb4e5e496c..4da55ab192ef2 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -93,7 +93,6 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); - // Event::send(entry, _timestamp); } } @@ -106,7 +105,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { void GCTracer::report_object_count() { KlassInfoTable* cit = ObjectCountClosure::get_table(); - if (cit == nullptr) { + if (cit == nullptr || !ObjectCountEventSender::should_send_event()) { return; } diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index b03b1d07c2b1d..143557bc991d4 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -47,4 +47,5 @@ bool ObjectCountClosure::should_send_event() { template bool ObjectCountClosure::should_send_event(); template bool ObjectCountClosure::should_send_event(); + #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index c53ae12da24f1..3729b1749aeca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -772,17 +772,10 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->verifier()->verify_roots_no_forwarded(); } - // Efficient implementation: { heap->tracer()->report_object_count(); } - // Naive implementation: - // { - // ShenandoahIsAliveClosure is_alive; - // heap->tracer()->report_object_count_after_gc(&is_alive, heap->workers()); - // } - if (!heap->cancelled_gc()) { _mark.finish_mark(); From 0d2a8a87401bbc2b0003f3666633810f776715ae Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 25 Jul 2025 03:27:55 +0000 Subject: [PATCH 051/104] Removed universe.hpp --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 143557bc991d4..431a4a8d97c5c 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -21,7 +21,7 @@ void ObjectCountClosure::reset_table() { bool ObjectCountClosure::check_table_exists() { - if (cit == nullptr && Universe::is_fully_initialized()) { + if (cit == nullptr) { static KlassInfoTable temp_table(false); cit = &temp_table; } From 15859c19a96398337790a62c37a41a91b06698af Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 25 Jul 2025 16:09:48 +0000 Subject: [PATCH 052/104] Removed mutex header file in objectCountClosure files --- src/hotspot/share/gc/shared/gcTrace.cpp | 1 - src/hotspot/share/gc/shared/objectCountClosure.cpp | 2 -- src/hotspot/share/gc/shared/objectCountClosure.hpp | 1 - src/jdk.jfr/share/conf/jfr/profile.jfc | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 4da55ab192ef2..b4f1ba8237340 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -123,7 +123,6 @@ 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); } diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 431a4a8d97c5c..2006b13b2b5be 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -3,8 +3,6 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" -#include "memory/universe.hpp" -#include "runtime/mutex.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 5d8fce77d4f90..592dcd101e2df 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -5,7 +5,6 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/allStatic.hpp" -#include "runtime/mutex.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/jdk.jfr/share/conf/jfr/profile.jfc b/src/jdk.jfr/share/conf/jfr/profile.jfc index d7b7b6e1921ad..5ffdc8d9e4dbf 100644 --- a/src/jdk.jfr/share/conf/jfr/profile.jfc +++ b/src/jdk.jfr/share/conf/jfr/profile.jfc @@ -360,7 +360,7 @@ - true + false From f555bfa7f45429e53a8b0a80941d2b9724d2c747 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 25 Jul 2025 16:34:46 +0000 Subject: [PATCH 053/104] Readded mutex header file in objectCountClosure files --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 2 ++ src/hotspot/share/gc/shared/objectCountClosure.hpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 2006b13b2b5be..431a4a8d97c5c 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -3,6 +3,8 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" +#include "memory/universe.hpp" +#include "runtime/mutex.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 592dcd101e2df..5d8fce77d4f90 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -5,6 +5,7 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/allStatic.hpp" +#include "runtime/mutex.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" From a7945461fc01c4d21feae673acb4f8ff271908d9 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 25 Jul 2025 18:26:22 +0000 Subject: [PATCH 054/104] Removed unnecessary atomic operations in merge_entry --- src/hotspot/share/memory/heapInspection.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 6d7103b9173c9..0b7512664fc06 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -246,10 +246,9 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { // elt may be null if it's a new klass for which we // could not allocate space for a new entry in the hashtable. if (elt != nullptr) { - elt->atomic_add_count(cie->count()); - size_t words_to_add = cie->words(); - elt->atomic_add_words(words_to_add); - Atomic::add(&_size_of_instances_in_words, words_to_add); + elt->set_count(elt->count() + cie->count()); + elt->set_words(elt->words() + cie->words()); + _size_of_instances_in_words += cie->words(); return true; } return false; From bbc5ff05d582f979f2cdfcf7c92dfc10f834c961 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 25 Jul 2025 21:46:11 +0000 Subject: [PATCH 055/104] Added comments for public methods in ObjectCountClosure --- src/hotspot/share/gc/shared/objectCountClosure.cpp | 2 -- src/hotspot/share/gc/shared/objectCountClosure.hpp | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 431a4a8d97c5c..2006b13b2b5be 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -3,8 +3,6 @@ #include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" -#include "memory/universe.hpp" -#include "runtime/mutex.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 5d8fce77d4f90..9c3f944c029d8 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -17,11 +17,16 @@ class ObjectCountClosure : public AllStatic { static KlassInfoTable* cit; public: + // Return false if allocation of KlassInfoTable failed. static bool check_table_exists(); + // Return false if object could not be recorded in the KlassInfoTable. static bool record_object(oop o); + // Returns the KlassInfoTable if it exists, otherwise returns nullptr. static KlassInfoTable* get_table(); + // Clear entries of the KlassInfoTable static void reset_table(); + // Returns true if event is enabled template static bool should_send_event(); }; From fc6b10166816d46e351188c1cd55611fedba4721 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Sun, 27 Jul 2025 00:51:18 +0000 Subject: [PATCH 056/104] KlassInfoEntry will be deleted after sending event for that entry --- src/hotspot/share/gc/shared/gcTrace.cpp | 3 ++- .../share/gc/shared/objectCountClosure.cpp | 4 ++-- .../share/gc/shared/objectCountClosure.hpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 18 ++++++++++++++++++ src/hotspot/share/memory/heapInspection.hpp | 3 +++ 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index b4f1ba8237340..242266af921b3 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -93,6 +93,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); + ObjectCountClosure::reset_table(entry); } } @@ -111,7 +112,7 @@ void GCTracer::report_object_count() { ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); cit->iterate(&event_sender); - ObjectCountClosure::reset_table(); + // ObjectCountClosure::reset_table(); } void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index 2006b13b2b5be..c9b30620a9050 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -10,11 +10,11 @@ KlassInfoTable* ObjectCountClosure::cit = nullptr; -void ObjectCountClosure::reset_table() { +void ObjectCountClosure::reset_table(KlassInfoEntry* entry) { if (!check_table_exists()) { return; } - cit->clear_entries(); + cit->delete_entry(entry); } diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 9c3f944c029d8..1e836abf93124 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -24,7 +24,7 @@ class ObjectCountClosure : public AllStatic { // Returns the KlassInfoTable if it exists, otherwise returns nullptr. static KlassInfoTable* get_table(); // Clear entries of the KlassInfoTable - static void reset_table(); + static void reset_table(KlassInfoEntry* entry); // Returns true if event is enabled template diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 0b7512664fc06..629549d3192b1 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -155,6 +155,19 @@ void KlassInfoBucket::empty() { } } +void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { + KlassInfoEntry* elt = _list; + while (elt != nullptr) { + KlassInfoEntry* next = elt->next(); + if (next == entry) { + elt->set_next(entry->next()); + delete entry; + return; + } + elt = next; + } +} + class KlassInfoTable::AllClassesFinder : public LockedClassesDo { KlassInfoTable *_table; public: @@ -254,6 +267,11 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { return false; } +void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { + uint idx = hash(entry->klass()) % _num_buckets; + _buckets[idx].remove_from_list(entry); +} + class KlassInfoTableMergeClosure : public KlassInfoClosure { private: KlassInfoTable* _dest; diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 8cc017c464480..b619cd2c734e0 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -67,6 +67,7 @@ class KlassInfoEntry: public CHeapObj { _do_print(false), _subclasses(nullptr) {} ~KlassInfoEntry(); + void set_next(KlassInfoEntry* next) { _next = next; } KlassInfoEntry* next() const { return _next; } bool is_equal(const Klass* k) { return k == _klass; } Klass* klass() const { return _klass; } @@ -103,6 +104,7 @@ class KlassInfoBucket: public CHeapObj { KlassInfoEntry* lookup(Klass* k); void initialize() { _list = nullptr; } void empty(); + void remove_from_list(KlassInfoEntry* entry); void iterate(KlassInfoClosure* cic); }; @@ -132,6 +134,7 @@ class KlassInfoTable: public StackObj { bool merge_entry(const KlassInfoEntry* cie); // Clears entries in the table void clear_entries(); + void delete_entry(KlassInfoEntry* entry); friend class KlassInfoHisto; friend class KlassHierarchy; }; From 0cdffed561655647c7306fed0901c81182b905cf Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 28 Jul 2025 16:18:25 +0000 Subject: [PATCH 057/104] Report object count outside of safepoint --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 3729b1749aeca..2c1ace3a95343 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -316,6 +316,8 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { heap->try_inject_alloc_failure(); VM_ShenandoahFinalMarkStartEvac op(this); VMThread::execute(&op); // jump to entry_final_mark under safepoint + assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); + heap->tracer()->report_object_count(); } void ShenandoahConcurrentGC::vmop_entry_init_update_refs() { @@ -772,9 +774,6 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->verifier()->verify_roots_no_forwarded(); } - { - heap->tracer()->report_object_count(); - } if (!heap->cancelled_gc()) { From 1f67cf56e41bea2d8c3c722444c9936c8b0cf7f1 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 29 Jul 2025 19:05:47 +0000 Subject: [PATCH 058/104] Create ObjectCountClosure to be a StackObj --- .../share/gc/shared/objectCountClosure.cpp | 23 +++++++++++-------- .../share/gc/shared/objectCountClosure.hpp | 5 +++- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountClosure.cpp b/src/hotspot/share/gc/shared/objectCountClosure.cpp index c9b30620a9050..1613f9a913458 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.cpp @@ -10,15 +10,7 @@ KlassInfoTable* ObjectCountClosure::cit = nullptr; -void ObjectCountClosure::reset_table(KlassInfoEntry* entry) { - if (!check_table_exists()) { - return; - } - cit->delete_entry(entry); - } - - -bool ObjectCountClosure::check_table_exists() { +bool ObjectCountClosure::initialize_table() { if (cit == nullptr) { static KlassInfoTable temp_table(false); cit = &temp_table; @@ -26,6 +18,13 @@ bool ObjectCountClosure::check_table_exists() { return !cit->allocation_failed(); } +bool ObjectCountClosure::check_table_exists() { + if (cit == nullptr) { + initialize_table(); + } + return cit != nullptr && !cit->allocation_failed(); +} + bool ObjectCountClosure::record_object(oop o) { if (!check_table_exists()) { return false; @@ -37,6 +36,12 @@ KlassInfoTable* ObjectCountClosure::get_table() { return check_table_exists() ? cit : nullptr; } +void ObjectCountClosure::reset_table(KlassInfoEntry* entry) { + if (!check_table_exists()) { + return; + } + cit->delete_entry(entry); +} template bool ObjectCountClosure::should_send_event() { diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp index 1e836abf93124..19d1a4116642b 100644 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ b/src/hotspot/share/gc/shared/objectCountClosure.hpp @@ -13,10 +13,12 @@ class KlassInfoEntry; class Klass; -class ObjectCountClosure : public AllStatic { +class ObjectCountClosure : public StackObj { static KlassInfoTable* cit; public: + // Initialize the KlassInfoTable + static bool initialize_table(); // Return false if allocation of KlassInfoTable failed. static bool check_table_exists(); // Return false if object could not be recorded in the KlassInfoTable. @@ -26,6 +28,7 @@ class ObjectCountClosure : public AllStatic { // Clear entries of the KlassInfoTable static void reset_table(KlassInfoEntry* entry); + // Returns true if event is enabled template static bool should_send_event(); From b2c7950c875441bc81c2f16345cfaf90cffd2710 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 31 Jul 2025 22:50:58 +0000 Subject: [PATCH 059/104] New closure that combines marking and object counting into one --- src/hotspot/share/gc/shared/gcTrace.cpp | 23 ++++++++----- src/hotspot/share/gc/shared/gcTrace.hpp | 4 ++- .../gc/shenandoah/shenandoahClosures.hpp | 24 +++++++++++++- .../shenandoah/shenandoahClosures.inline.hpp | 4 +-- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- .../share/gc/shenandoah/shenandoahHeap.cpp | 8 +++++ .../share/gc/shenandoah/shenandoahHeap.hpp | 5 ++- .../share/gc/shenandoah/shenandoahMark.cpp | 17 +++++++--- .../share/gc/shenandoah/shenandoahMark.hpp | 6 ++-- .../gc/shenandoah/shenandoahMark.inline.hpp | 30 ++++++++--------- .../shenandoahObjectCountClosure.hpp | 27 +++++++++++++++ src/hotspot/share/memory/heapInspection.cpp | 33 ++++++++++--------- src/hotspot/share/memory/heapInspection.hpp | 2 -- 13 files changed, 131 insertions(+), 54 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 242266af921b3..fd84c3a6ae785 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -82,18 +82,20 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; const size_t _total_size_in_words; const Ticks _timestamp; + KlassInfoTable* _cit; public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), - _timestamp(timestamp) + _timestamp(timestamp), + _cit(cit) {} virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); - ObjectCountClosure::reset_table(entry); + _cit->delete_entry(entry); } } @@ -104,15 +106,16 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -void GCTracer::report_object_count() { - KlassInfoTable* cit = ObjectCountClosure::get_table(); - if (cit == nullptr || !ObjectCountEventSender::should_send_event()) { +// Assumes that the get_cit a member of the heap class +template +void GCTracer::report_object_count(T* heap) { + KlassInfoTable* cit = heap->get_cit(); + if (cit == nullptr && !ObjectCountEventSender::should_send_event()) { return; } - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); - // ObjectCountClosure::reset_table(); } void GCTracer::report_object_count_after_gc(BoolObjectClosure* is_alive_cl, WorkerThreads* workers) { @@ -124,7 +127,7 @@ 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); cit.iterate(&event_sender); } } @@ -203,3 +206,5 @@ void ParallelOldTracer::report_dense_prefix(void* dense_prefix) { void OldGCTracer::report_concurrent_mode_failure() { send_concurrent_mode_failure_event(); } + +template void GCTracer::report_object_count(ShenandoahHeap* heap); diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 72b6300fb16f1..38620c0674ce7 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -104,7 +104,9 @@ class GCTracer { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; // Sends event data to the ObjectCountAfterGC event - void report_object_count() NOT_SERVICES_RETURN; + template + void report_object_count(T* heap) 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/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 0c223ee3128be..efcc1ee9c1561 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -27,6 +27,7 @@ #include "code/nmethod.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "memory/iterator.hpp" #include "runtime/javaThread.hpp" @@ -35,6 +36,7 @@ class BarrierSetNMethod; class ShenandoahBarrierSet; class ShenandoahHeap; class ShenandoahMarkingContext; +class ShenandoahObjectCountClosure; class ShenandoahReferenceProcessor; class SATBMarkQueueSet; @@ -73,7 +75,7 @@ class ShenandoahMarkRefsSuperClosure : public ShenandoahSuperClosure { protected: template - void work(T *p); + bool work(T *p); public: inline ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp, ShenandoahObjToScanQueue* old_q); @@ -106,6 +108,26 @@ class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { virtual void do_oop(oop* p) { do_oop_work(p); } }; +template +class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure { +private: + ShenandoahObjectCountClosure* _count; + template + inline void do_oop_work(T* p) { + bool newly_marked = work(p); + if (newly_marked) { + _count->do_oop(p); + } + } + +public: + ShenandoahMarkRefsAndCountClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp, ShenandoahObjToScanQueue* old_q, ShenandoahObjectCountClosure* count) : + ShenandoahMarkRefsSuperClosure(q, rp, old_q), _count(count) {}; + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } +}; + class ShenandoahForwardedIsAliveClosure : public BoolObjectClosure { private: ShenandoahMarkingContext* const _mark_context; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index 725e4e6e3e9f9..cf642f762b6f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -77,8 +77,8 @@ ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToSc _weak(false) {} template -inline void ShenandoahMarkRefsSuperClosure::work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, _weak); +inline bool ShenandoahMarkRefsSuperClosure::work(T* p) { + return ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, _weak); } ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 2170fb61f06f0..3fc91ed9097bf 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -317,7 +317,7 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { VM_ShenandoahFinalMarkStartEvac op(this); VMThread::execute(&op); // jump to entry_final_mark under safepoint assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); - heap->tracer()->report_object_count(); + heap->tracer()->report_object_count(heap); } void ShenandoahConcurrentGC::vmop_entry_init_update_refs() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 71d4824562b32..dadf3dc4775e9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -533,6 +533,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : _active_generation(nullptr), _initial_size(0), _committed(0), + _cit(nullptr), _max_workers(MAX3(ConcGCThreads, ParallelGCThreads, 1U)), _workers(nullptr), _safepoint_workers(nullptr), @@ -686,6 +687,9 @@ void ShenandoahHeap::post_initialize() { _safepoint_workers->set_initialize_gclab(); } + static KlassInfoTable cit(false); + _cit = &cit; + JFR_ONLY(ShenandoahJFRSupport::register_jfr_type_serializers();) } @@ -803,6 +807,10 @@ void ShenandoahHeap::set_soft_max_capacity(size_t v) { Atomic::store(&_soft_max_size, v); } +KlassInfoTable* ShenandoahHeap::get_cit() { + return _cit; +} + size_t ShenandoahHeap::min_capacity() const { return _minimum_size; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 4a9b990686385..6dccf5e219c43 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -43,6 +43,7 @@ #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahUnload.hpp" +#include "memory/heapInspection.hpp" #include "memory/metaspace.hpp" #include "services/memoryManager.hpp" #include "utilities/globalDefinitions.hpp" @@ -228,7 +229,8 @@ class ShenandoahHeap : public CollectedHeap { shenandoah_padding(0); volatile size_t _committed; shenandoah_padding(1); - + + KlassInfoTable* _cit; void increase_used(const ShenandoahAllocRequest& req); public: @@ -251,6 +253,7 @@ class ShenandoahHeap : public CollectedHeap { size_t committed() const; void set_soft_max_capacity(size_t v); + KlassInfoTable* get_cit(); // ---------- Periodic Tasks // diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 2a4149ee44dc4..08bb944433fac 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -24,7 +24,7 @@ */ - +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" @@ -69,9 +69,18 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); } else { - using Closure = ShenandoahMarkRefsClosure; - Closure cl(q, rp, old_q); - mark_loop_work(&cl, ld, w, t, req); + bool object_count = ObjectCountEventSender::should_send_event(); + if (object_count) { + KlassInfoTable* _cit = heap->get_cit(); + ShenandoahObjectCountClosure _count(_cit); + using Closure = ShenandoahMarkRefsAndCountClosure; + Closure cl(q, rp, old_q, &_count); + mark_loop_work(&cl, ld, w, t, req); + } else { + using Closure = ShenandoahMarkRefsClosure; + Closure cl(q, rp, old_q); + mark_loop_work(&cl, ld, w, t, req); + } } heap->flush_liveness_cache(w); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 4aef14f2c9aba..5675bfc3f5fa5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -57,7 +57,7 @@ class ShenandoahMark: public StackObj { public: template - static inline void mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak); + static inline bool mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak); // Loom support void start_mark(); @@ -99,9 +99,9 @@ class ShenandoahMark: public StackObj { static bool in_generation(ShenandoahHeap* const heap, oop obj); template - static void mark_non_generational_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak); + static bool mark_non_generational_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak); - static void mark_ref(ShenandoahObjToScanQueue* q, + static bool mark_ref(ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak, oop obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 718c293923f9c..5655025f78b46 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -47,7 +47,6 @@ #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) { @@ -294,10 +293,11 @@ bool ShenandoahMark::in_generation(ShenandoahHeap* const heap, oop obj) { } template -inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { +inline bool ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { // Note: This is a very hot code path, so the code should be conditional on GENERATION template // parameter where possible, in order to generate the most efficient code. + bool marked = false; T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); @@ -306,7 +306,7 @@ inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, shenandoah_assert_not_forwarded(p, obj); shenandoah_assert_not_in_cset_except(p, obj, heap->cancelled_gc()); if (in_generation(heap, obj)) { - mark_ref(q, mark_context, weak, obj); + marked = mark_ref(q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); if (GENERATION == YOUNG && heap->is_in_old(p)) { // Mark card as dirty because remembered set scanning still finds interesting pointer. @@ -317,7 +317,7 @@ inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, } } else if (old_q != nullptr) { // Young mark, bootstrapping old_q or concurrent with old_q marking. - mark_ref(old_q, mark_context, weak, obj); + marked = mark_ref(old_q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); } else if (GENERATION == OLD) { // Old mark, found a young pointer. @@ -327,35 +327,38 @@ inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, } } } + return marked; } template<> -inline void ShenandoahMark::mark_through_ref(oop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { - mark_non_generational_ref(p, q, mark_context, weak); +inline bool ShenandoahMark::mark_through_ref(oop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { + return mark_non_generational_ref(p, q, mark_context, weak); } template<> -inline void ShenandoahMark::mark_through_ref(narrowOop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { - mark_non_generational_ref(p, q, mark_context, weak); +inline bool ShenandoahMark::mark_through_ref(narrowOop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { + return mark_non_generational_ref(p, q, mark_context, weak); } template -inline void ShenandoahMark::mark_non_generational_ref(T* p, ShenandoahObjToScanQueue* q, +inline bool ShenandoahMark::mark_non_generational_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak) { oop o = RawAccess<>::oop_load(p); + bool marked = false; if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); shenandoah_assert_not_forwarded(p, obj); shenandoah_assert_not_in_cset_except(p, obj, ShenandoahHeap::heap()->cancelled_gc()); - mark_ref(q, mark_context, weak, obj); + marked = mark_ref(q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); } + return marked; } -inline void ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, +inline bool ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak, oop obj) { bool skip_live = false; @@ -368,11 +371,8 @@ inline void ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, if (marked) { bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); assert(pushed, "overflow queue should always succeed pushing"); - bool should_record = ObjectCountClosure::should_send_event(); - if (should_record) { - ObjectCountClosure::record_object(obj); - } } + return marked; } ShenandoahObjToScanQueueSet* ShenandoahMark::task_queues() const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp new file mode 100644 index 0000000000000..37d2207209620 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -0,0 +1,27 @@ +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP +#include "memory/heapInspection.hpp" +#include "oops/access.hpp" +#include "oops/compressedOops.inline.hpp" +#include "oops/oop.inline.hpp" + +class ShenandoahObjectCountClosure { + private: + KlassInfoTable* _cit; + + template + inline void do_oop_work(T* p) { + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + _cit->record_instance(obj); + } + } + + public: + ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} + inline void do_oop(narrowOop* o) { do_oop_work(o); } + inline void do_oop(oop* o) { do_oop_work(o); } +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 629549d3192b1..9a3f5f040e992 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -39,6 +39,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" +#include "iostream" // HeapInspection @@ -140,8 +141,9 @@ KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { void KlassInfoBucket::iterate(KlassInfoClosure* cic) { KlassInfoEntry* elt = _list; while (elt != nullptr) { + KlassInfoEntry* next = elt->next(); cic->do_cinfo(elt); - elt = elt->next(); + elt = next; } } @@ -155,17 +157,28 @@ void KlassInfoBucket::empty() { } } +// Deletes the KlassInfoEntry in the list void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { + // If entry is the head, delete it + if (_list == entry) { + KlassInfoEntry* next = _list->next(); + _list = next; + delete entry; + return; + } + KlassInfoEntry* elt = _list; + KlassInfoEntry* prev = nullptr; while (elt != nullptr) { KlassInfoEntry* next = elt->next(); - if (next == entry) { - elt->set_next(entry->next()); - delete entry; + if (elt == entry) { + prev->set_next(next); + delete elt; return; } + prev = elt; elt = next; - } + } } class KlassInfoTable::AllClassesFinder : public LockedClassesDo { @@ -284,16 +297,6 @@ class KlassInfoTableMergeClosure : public KlassInfoClosure { bool success() { return _success; } }; -void KlassInfoTable::clear_entries() { - if (_buckets != nullptr) { - for (int index = 0; index < _num_buckets; index++) { - _buckets[index].empty(); - _buckets[index].initialize(); - } - _size_of_instances_in_words = 0; - } -} - // merge from table bool KlassInfoTable::merge(KlassInfoTable* table) { KlassInfoTableMergeClosure closure(this); diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index b619cd2c734e0..3d2675ea0301a 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -132,8 +132,6 @@ class KlassInfoTable: public StackObj { size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); - // Clears entries in the table - void clear_entries(); void delete_entry(KlassInfoEntry* entry); friend class KlassInfoHisto; friend class KlassHierarchy; From 88f5be11627f9f394c0ae71283cc0ce51ddccb26 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 31 Jul 2025 23:04:46 +0000 Subject: [PATCH 060/104] No longer need ObjectCountClosure class --- .../share/gc/shared/objectCountClosure.cpp | 54 ------------------- .../share/gc/shared/objectCountClosure.hpp | 37 ------------- 2 files changed, 91 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/objectCountClosure.cpp delete 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 deleted file mode 100644 index 1613f9a913458..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountClosure.cpp +++ /dev/null @@ -1,54 +0,0 @@ - -#include "gc/shared/objectCountClosure.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 - -KlassInfoTable* ObjectCountClosure::cit = nullptr; - -bool ObjectCountClosure::initialize_table() { - if (cit == nullptr) { - static KlassInfoTable temp_table(false); - cit = &temp_table; - } - return !cit->allocation_failed(); -} - -bool ObjectCountClosure::check_table_exists() { - if (cit == nullptr) { - initialize_table(); - } - return cit != nullptr && !cit->allocation_failed(); -} - -bool ObjectCountClosure::record_object(oop o) { - if (!check_table_exists()) { - return false; - } - return cit->record_instance(o); -} - -KlassInfoTable* ObjectCountClosure::get_table() { - return check_table_exists() ? cit : nullptr; -} - -void ObjectCountClosure::reset_table(KlassInfoEntry* entry) { - if (!check_table_exists()) { - return; - } - cit->delete_entry(entry); -} - -template -bool ObjectCountClosure::should_send_event() { - return ObjectCountEventSender::should_send_event(); -} - -template bool ObjectCountClosure::should_send_event(); -template bool ObjectCountClosure::should_send_event(); - -#endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountClosure.hpp b/src/hotspot/share/gc/shared/objectCountClosure.hpp deleted file mode 100644 index 19d1a4116642b..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountClosure.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#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/allStatic.hpp" -#include "runtime/mutex.hpp" -#include "memory/heapInspection.hpp" -#include "utilities/macros.hpp" -#include "utilities/ticks.hpp" - -class KlassInfoEntry; -class Klass; - -class ObjectCountClosure : public StackObj { - static KlassInfoTable* cit; - -public: - // Initialize the KlassInfoTable - static bool initialize_table(); - // Return false if allocation of KlassInfoTable failed. - static bool check_table_exists(); - // Return false if object could not be recorded in the KlassInfoTable. - static bool record_object(oop o); - // Returns the KlassInfoTable if it exists, otherwise returns nullptr. - static KlassInfoTable* get_table(); - // Clear entries of the KlassInfoTable - static void reset_table(KlassInfoEntry* entry); - - - // Returns true if event is enabled - template - static bool should_send_event(); -}; - -#endif // SHARE_GC_SHARED_OBJECTCOUNTCLOSURE_HPP From f5c69bce5fda97689e0ed4eb658563b72ab310ed Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 31 Jul 2025 23:58:58 +0000 Subject: [PATCH 061/104] Removed objectCountClosure.hpp in gcTrace --- src/hotspot/share/gc/shared/gcTrace.cpp | 4 +-- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 -- .../shenandoahObjectCountClosure.hpp | 30 ++++++++++--------- src/hotspot/share/memory/heapInspection.cpp | 1 - src/hotspot/share/memory/heapInspection.hpp | 2 ++ 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index fd84c3a6ae785..e3534dabd8818 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,10 +27,10 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "jfr/jfrEvents.hpp" -#include "gc/shared/objectCountClosure.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" #include "runtime/os.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 3fc91ed9097bf..ea406a2313905 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -769,8 +769,6 @@ void ShenandoahConcurrentGC::op_final_mark() { heap->verifier()->verify_roots_no_forwarded(); } - - if (!heap->cancelled_gc()) { _mark.finish_mark(); assert(!heap->cancelled_gc(), "STW mark cannot OOM"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index 37d2207209620..48b5311e24593 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -6,22 +6,24 @@ #include "oops/oop.inline.hpp" class ShenandoahObjectCountClosure { - private: - KlassInfoTable* _cit; +private: + KlassInfoTable* _cit; - template - inline void do_oop_work(T* p) { - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - _cit->record_instance(obj); - } - } + template + inline void do_oop_work(T* p) { + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + _cit->record_instance(obj); + } + } - public: - ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} - inline void do_oop(narrowOop* o) { do_oop_work(o); } - inline void do_oop(oop* o) { do_oop_work(o); } +public: + ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} + // Record the object's instance in the KlassInfoTable + inline void do_oop(narrowOop* o) { do_oop_work(o); } + // Record the object's instance in the KlassInfoTable + inline void do_oop(oop* o) { do_oop_work(o); } }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 9a3f5f040e992..031cca1f147b4 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -157,7 +157,6 @@ void KlassInfoBucket::empty() { } } -// Deletes the KlassInfoEntry in the list void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { // If entry is the head, delete it if (_list == entry) { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 3d2675ea0301a..2f65bdbebed15 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -104,6 +104,7 @@ class KlassInfoBucket: public CHeapObj { KlassInfoEntry* lookup(Klass* k); void initialize() { _list = nullptr; } void empty(); + // Deletes the KlassInfoEntry in the list void remove_from_list(KlassInfoEntry* entry); void iterate(KlassInfoClosure* cic); }; @@ -132,6 +133,7 @@ class KlassInfoTable: public StackObj { size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); + // Deletes the KlassInfoEntry in the list void delete_entry(KlassInfoEntry* entry); friend class KlassInfoHisto; friend class KlassHierarchy; From 89cd068ee0bfeb70b139eaff5561f5b970c74c26 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 1 Aug 2025 18:39:53 +0000 Subject: [PATCH 062/104] Removed cit member from the ObjectCountEventSenderClosure --- src/hotspot/share/gc/shared/gcTrace.cpp | 13 +++++-------- src/hotspot/share/memory/heapInspection.cpp | 1 + 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index e3534dabd8818..c9d4d69a8cf88 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -82,20 +82,17 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; const size_t _total_size_in_words; const Ticks _timestamp; - KlassInfoTable* _cit; public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit) : + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), - _timestamp(timestamp), - _cit(cit) + _timestamp(timestamp) {} virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); - _cit->delete_entry(entry); } } @@ -106,7 +103,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -// Assumes that the get_cit a member of the heap class +// Assumes that the get_cit is a member of the heap class template void GCTracer::report_object_count(T* heap) { KlassInfoTable* cit = heap->get_cit(); @@ -114,7 +111,7 @@ void GCTracer::report_object_count(T* heap) { return; } - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); cit->iterate(&event_sender); } @@ -127,7 +124,7 @@ 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(), &cit); + ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); cit.iterate(&event_sender); } } diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 031cca1f147b4..bbbb0a9c78f0c 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -143,6 +143,7 @@ void KlassInfoBucket::iterate(KlassInfoClosure* cic) { while (elt != nullptr) { KlassInfoEntry* next = elt->next(); cic->do_cinfo(elt); + this->remove_from_list(elt); elt = next; } } From 2a932fb8a16ba115cf7d8ce290884c89b5fcfc9a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 1 Aug 2025 18:58:46 +0000 Subject: [PATCH 063/104] Restored cit in object count event sender --- src/hotspot/share/gc/shared/gcTrace.cpp | 13 ++++++++----- src/hotspot/share/memory/heapInspection.cpp | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index c9d4d69a8cf88..e3534dabd8818 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -82,17 +82,20 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; const size_t _total_size_in_words; const Ticks _timestamp; + KlassInfoTable* _cit; public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), - _timestamp(timestamp) + _timestamp(timestamp), + _cit(cit) {} virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); + _cit->delete_entry(entry); } } @@ -103,7 +106,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -// Assumes that the get_cit is a member of the heap class +// Assumes that the get_cit a member of the heap class template void GCTracer::report_object_count(T* heap) { KlassInfoTable* cit = heap->get_cit(); @@ -111,7 +114,7 @@ void GCTracer::report_object_count(T* heap) { return; } - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); } @@ -124,7 +127,7 @@ 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); cit.iterate(&event_sender); } } diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index bbbb0a9c78f0c..031cca1f147b4 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -143,7 +143,6 @@ void KlassInfoBucket::iterate(KlassInfoClosure* cic) { while (elt != nullptr) { KlassInfoEntry* next = elt->next(); cic->do_cinfo(elt); - this->remove_from_list(elt); elt = next; } } From e06c6984831f8f9a3d480658c1c9c009de0ba080 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 1 Aug 2025 19:22:52 +0000 Subject: [PATCH 064/104] Entry is always at the head when iterating --- src/hotspot/share/memory/heapInspection.cpp | 15 --------------- src/hotspot/share/memory/heapInspection.hpp | 1 - 2 files changed, 16 deletions(-) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 031cca1f147b4..33a25e1c33d73 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -39,7 +39,6 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/stack.inline.hpp" -#include "iostream" // HeapInspection @@ -158,26 +157,12 @@ void KlassInfoBucket::empty() { } void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { - // If entry is the head, delete it if (_list == entry) { KlassInfoEntry* next = _list->next(); _list = next; delete entry; return; } - - KlassInfoEntry* elt = _list; - KlassInfoEntry* prev = nullptr; - while (elt != nullptr) { - KlassInfoEntry* next = elt->next(); - if (elt == entry) { - prev->set_next(next); - delete elt; - return; - } - prev = elt; - elt = next; - } } class KlassInfoTable::AllClassesFinder : public LockedClassesDo { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 2f65bdbebed15..375503df73e57 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -67,7 +67,6 @@ class KlassInfoEntry: public CHeapObj { _do_print(false), _subclasses(nullptr) {} ~KlassInfoEntry(); - void set_next(KlassInfoEntry* next) { _next = next; } KlassInfoEntry* next() const { return _next; } bool is_equal(const Klass* k) { return k == _klass; } Klass* klass() const { return _klass; } From bb6fffd917f8fdfc758ffd1de55b29e3e6077a72 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 1 Aug 2025 20:46:07 +0000 Subject: [PATCH 065/104] Delete entry in the middle of bucket --- src/hotspot/share/memory/heapInspection.cpp | 11 +++++++++++ src/hotspot/share/memory/heapInspection.hpp | 1 + 2 files changed, 12 insertions(+) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 33a25e1c33d73..e736165a70704 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -163,6 +163,17 @@ void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { delete entry; return; } + + KlassInfoEntry* current = _list; + while (current != nullptr && current->next() != entry) { + current = current->next(); + } + + if (current != nullptr && current->next() == entry) { + KlassInfoEntry* next = entry->next(); + current->set_next(next); + delete entry; + } } class KlassInfoTable::AllClassesFinder : public LockedClassesDo { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 375503df73e57..2f65bdbebed15 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -67,6 +67,7 @@ class KlassInfoEntry: public CHeapObj { _do_print(false), _subclasses(nullptr) {} ~KlassInfoEntry(); + void set_next(KlassInfoEntry* next) { _next = next; } KlassInfoEntry* next() const { return _next; } bool is_equal(const Klass* k) { return k == _klass; } Klass* klass() const { return _klass; } From 11214694eed8ec44d4ffd26895745023aa9c52d8 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 4 Aug 2025 21:14:27 +0000 Subject: [PATCH 066/104] Assert to check if KlassInfoEntry was deleted + comments --- src/hotspot/share/gc/shared/gcTrace.cpp | 2 ++ src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 8 ++++++-- src/hotspot/share/memory/heapInspection.hpp | 5 +++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index e3534dabd8818..fac401050aac1 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -38,6 +38,8 @@ #include "utilities/macros.hpp" #include "utilities/ticks.hpp" +class ShenandoahHeap; + bool GCTracer::should_report_cpu_time_event() const { return should_send_cpu_time_event(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index efcc1ee9c1561..530bb7a4e4361 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -36,7 +36,6 @@ class BarrierSetNMethod; class ShenandoahBarrierSet; class ShenandoahHeap; class ShenandoahMarkingContext; -class ShenandoahObjectCountClosure; class ShenandoahReferenceProcessor; class SATBMarkQueueSet; @@ -112,6 +111,7 @@ template class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure { private: ShenandoahObjectCountClosure* _count; + template inline void do_oop_work(T* p) { bool newly_marked = work(p); diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index e736165a70704..8904d7fc6e955 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -156,14 +156,15 @@ void KlassInfoBucket::empty() { } } -void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { +void KlassInfoBucket::remove_from_list(KlassInfoEntry*& entry) { if (_list == entry) { KlassInfoEntry* next = _list->next(); _list = next; delete entry; + entry = nullptr; return; } - + KlassInfoEntry* current = _list; while (current != nullptr && current->next() != entry) { current = current->next(); @@ -173,7 +174,10 @@ void KlassInfoBucket::remove_from_list(KlassInfoEntry* entry) { KlassInfoEntry* next = entry->next(); current->set_next(next); delete entry; + entry = nullptr; } + + assert(entry == nullptr, "Entry should be deleted"); } class KlassInfoTable::AllClassesFinder : public LockedClassesDo { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 2f65bdbebed15..5f3b0cb8769eb 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -104,8 +104,9 @@ class KlassInfoBucket: public CHeapObj { KlassInfoEntry* lookup(Klass* k); void initialize() { _list = nullptr; } void empty(); - // Deletes the KlassInfoEntry in the list - void remove_from_list(KlassInfoEntry* entry); + // Remove from the bucket list, and delete `entry`. + // `entry` must exist in the list. + void remove_from_list(KlassInfoEntry*& entry); void iterate(KlassInfoClosure* cic); }; From 92ab0cb43a90ba8760b38b4258d9d998f55afc48 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 4 Aug 2025 22:46:58 +0000 Subject: [PATCH 067/104] Removed explicit template instantiation and added test for ObjectCountAfterGC to Shenandoah --- src/hotspot/share/gc/shared/gcTrace.cpp | 1 - .../gc/shared/objectCountEventSender.cpp | 53 ------------------- .../gc/shared/objectCountEventSender.hpp | 40 +++++++++++++- .../gc/shenandoah/shenandoahClosures.hpp | 1 + ...ObjectCountAfterGCEventWithShenandoah.java | 40 ++++++++++++++ 5 files changed, 80 insertions(+), 55 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index fac401050aac1..b9a24fd4b4873 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -38,7 +38,6 @@ #include "utilities/macros.hpp" #include "utilities/ticks.hpp" -class ShenandoahHeap; bool GCTracer::should_report_cpu_time_event() const { return should_send_cpu_time_event(); diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index 7a4a9e10d6713..e36cda2c8434c 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -23,23 +23,7 @@ */ -#include "gc/shared/gcId.hpp" #include "gc/shared/objectCountEventSender.hpp" -#include "jfr/jfrEvents.hpp" -#include "runtime/mutex.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; @@ -50,40 +34,3 @@ void ObjectCountEventSender::enable_requestable_event() { 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 index 2a3208ef2b375..093a83e4b8cc1 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -26,10 +26,11 @@ #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP #include "memory/allStatic.hpp" +#include "memory/heapInspection.hpp" +#include "jfr/jfrEvents.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" - #if INCLUDE_SERVICES class KlassInfoEntry; @@ -52,6 +53,43 @@ class ObjectCountEventSender : public AllStatic { static bool should_send_event(); }; +template +bool ObjectCountEventSender::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || Event::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + +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); + } +} + #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 530bb7a4e4361..4fd27fe07067c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -114,6 +114,7 @@ class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure template inline void do_oop_work(T* p) { + // If the object was not previously marked, then it is considered newly marked and we record it's instance in the KlassInfoTable bool newly_marked = work(p); if (newly_marked) { _count->do_oop(p); diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java new file mode 100644 index 0000000000000..d99bf8d536b97 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +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 != true + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseShenandoahGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithShenandoah + */ +public class TestObjectCountAfterGCEventWithShenandoah { + public static void main(String[] args) throws Exception { + ObjectCountAfterGCEvent.test(GCHelper.gcShenandoah); + } +} From 0075cea36860ae3333794aefc97aaa202ee5c66e Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 5 Aug 2025 00:04:21 +0000 Subject: [PATCH 068/104] Subtract the total object size from the total table size to fix should_send_event issue --- src/hotspot/share/gc/shared/gcTrace.cpp | 6 +++--- src/hotspot/share/memory/heapInspection.cpp | 4 +++- src/hotspot/share/memory/heapInspection.hpp | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index b9a24fd4b4873..1512f43554515 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -81,7 +81,7 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con template class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; - const size_t _total_size_in_words; + size_t _total_size_in_words; const Ticks _timestamp; KlassInfoTable* _cit; @@ -96,7 +96,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); - _cit->delete_entry(entry); + _cit->delete_entry(entry, &_total_size_in_words); } } @@ -107,7 +107,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -// Assumes that the get_cit a member of the heap class +// Assumes that the get_cit is a member of the heap class template void GCTracer::report_object_count(T* heap) { KlassInfoTable* cit = heap->get_cit(); diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 8904d7fc6e955..dbf86866e6d84 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -279,9 +279,11 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { return false; } -void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { +void KlassInfoTable::delete_entry(KlassInfoEntry* entry, size_t* total_table_size) { uint idx = hash(entry->klass()) % _num_buckets; + size_t total_entry_size = entry->words(); _buckets[idx].remove_from_list(entry); + *total_table_size -= total_entry_size; } class KlassInfoTableMergeClosure : public KlassInfoClosure { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 5f3b0cb8769eb..fb6a3827bc82b 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -135,7 +135,7 @@ class KlassInfoTable: public StackObj { bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); // Deletes the KlassInfoEntry in the list - void delete_entry(KlassInfoEntry* entry); + void delete_entry(KlassInfoEntry* entry, size_t* total_table_size); friend class KlassInfoHisto; friend class KlassHierarchy; }; From 120b290b9c4db4b8312938a6d8c8eaf26a72977a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 5 Aug 2025 00:29:39 +0000 Subject: [PATCH 069/104] Put ShenandoahMarkRefsAndCountClosure at appropriate places --- .../gc/shenandoah/shenandoahConcurrentMark.cpp | 15 +++++++++++++-- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index facba2236be81..b4793d9e14ea4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -44,6 +44,9 @@ #include "memory/resourceArea.hpp" #include "runtime/continuation.hpp" #include "runtime/threads.hpp" +#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" + template class ShenandoahConcurrentMarkingTask : public WorkerTask { @@ -170,8 +173,16 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id); ShenandoahObjToScanQueue* old_q = (_old_queue_set == nullptr) ? nullptr : _old_queue_set->queue(worker_id); - ShenandoahMarkRefsClosure cl(q, _rp, old_q); - _root_scanner.roots_do(&cl, worker_id); + bool object_count = ObjectCountEventSender::should_send_event(); + if (object_count) { + KlassInfoTable* _cit = ShenandoahHeap::heap()->get_cit(); + ShenandoahObjectCountClosure _count(_cit); + ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); + _root_scanner.roots_do(&cl, worker_id); + } else { + ShenandoahMarkRefsClosure cl(q, _rp, old_q); + _root_scanner.roots_do(&cl, worker_id); + } } void ShenandoahConcurrentMark::mark_concurrent_roots() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index c2bfea664fdcf..4545f9cc073da 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -36,6 +36,8 @@ #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" +#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" class ShenandoahSTWMarkTask : public WorkerTask { private: @@ -122,8 +124,16 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { case NON_GEN: { - ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); - _root_scanner.roots_do(&init_mark, worker_id); + bool object_count = ObjectCountEventSender::should_send_event(); + if (object_count) { + KlassInfoTable* _cit = ShenandoahHeap::heap()->get_cit(); + ShenandoahObjectCountClosure _count(_cit); + ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); + _root_scanner.roots_do(&init_mark, worker_id); + } else { + ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); + _root_scanner.roots_do(&init_mark, worker_id); + } break; } case GLOBAL: { From 5ae65633944310278b3f64f4632a9206d3048af0 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 5 Aug 2025 17:33:13 +0000 Subject: [PATCH 070/104] Removed redundant check to see if object is null --- .../share/gc/shenandoah/shenandoahObjectCountClosure.hpp | 6 ++---- src/hotspot/share/memory/heapInspection.cpp | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index 48b5311e24593..094d84cfb0e32 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -12,10 +12,8 @@ class ShenandoahObjectCountClosure { template inline void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - _cit->record_instance(obj); - } + oop obj = CompressedOops::decode_not_null(o); + _cit->record_instance(obj); } public: diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index dbf86866e6d84..fbfc14b7d5b03 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -140,6 +140,8 @@ KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { void KlassInfoBucket::iterate(KlassInfoClosure* cic) { KlassInfoEntry* elt = _list; while (elt != nullptr) { + // The remove_from_list method will delete elt if ObjectCountEventSenderClosure decides to send the event + // If the event is sent, we should save the next entry of the bucket and define elt as that next entry, since could be deleted KlassInfoEntry* next = elt->next(); cic->do_cinfo(elt); elt = next; From 911df7b9e369452a31fe3134c69bf64e75fbb178 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Tue, 5 Aug 2025 19:44:41 +0000 Subject: [PATCH 071/104] Testing thread local KlassInfoTables --- src/hotspot/share/gc/shared/gcTrace.cpp | 6 +++++- .../shenandoah/shenandoahConcurrentMark.cpp | 7 ++++--- .../share/gc/shenandoah/shenandoahMark.cpp | 3 ++- .../shenandoahObjectCountClosure.cpp | 20 +++++++++++++++++++ .../shenandoahObjectCountClosure.hpp | 12 +++++++++-- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 3 ++- src/hotspot/share/memory/heapInspection.cpp | 9 ++++----- src/hotspot/share/memory/heapInspection.hpp | 4 ---- 8 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 1512f43554515..bc729f1adb4b1 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -37,6 +37,8 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" +#include "iostream" bool GCTracer::should_report_cpu_time_event() const { @@ -111,10 +113,12 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { template void GCTracer::report_object_count(T* heap) { KlassInfoTable* cit = heap->get_cit(); + ShenandoahObjectCountClosure t; + KlassInfoTable* new_cit = t.get_table(); + if (cit == nullptr && !ObjectCountEventSender::should_send_event()) { return; } - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index b4793d9e14ea4..814e7425a0745 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -176,12 +176,13 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { bool object_count = ObjectCountEventSender::should_send_event(); if (object_count) { KlassInfoTable* _cit = ShenandoahHeap::heap()->get_cit(); - ShenandoahObjectCountClosure _count(_cit); + ShenandoahObjectCountClosure _count; ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); _root_scanner.roots_do(&cl, worker_id); + _count.merge_tables(_cit); } else { - ShenandoahMarkRefsClosure cl(q, _rp, old_q); - _root_scanner.roots_do(&cl, worker_id); + ShenandoahMarkRefsClosure cl(q, _rp, old_q); + _root_scanner.roots_do(&cl, worker_id); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 08bb944433fac..edf2267f891c0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -72,10 +72,11 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe bool object_count = ObjectCountEventSender::should_send_event(); if (object_count) { KlassInfoTable* _cit = heap->get_cit(); - ShenandoahObjectCountClosure _count(_cit); + ShenandoahObjectCountClosure _count; using Closure = ShenandoahMarkRefsAndCountClosure; Closure cl(q, rp, old_q, &_count); mark_loop_work(&cl, ld, w, t, req); + _count.merge_tables(_cit); } else { using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp, old_q); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp new file mode 100644 index 0000000000000..a7a8f8d5707a6 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -0,0 +1,20 @@ +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" + +thread_local KlassInfoTable* ShenandoahObjectCountClosure::_cit = nullptr; + +// Change the return type to be a boolean +void ShenandoahObjectCountClosure::initialize_table() { + if (_cit == nullptr) { + static thread_local KlassInfoTable temp_table(false); + _cit = &temp_table; + } +} + +void ShenandoahObjectCountClosure::merge_tables(KlassInfoTable* main_cit) { + if (main_cit == nullptr || _cit == nullptr) { + return; + } + + bool success = main_cit->merge(_cit); + assert(success, "Failed to merge thread-local table"); +} \ No newline at end of file diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index 094d84cfb0e32..da7055feb0350 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -1,13 +1,15 @@ #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP #define SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP + #include "memory/heapInspection.hpp" #include "oops/access.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" + class ShenandoahObjectCountClosure { private: - KlassInfoTable* _cit; + static thread_local KlassInfoTable* _cit; template inline void do_oop_work(T* p) { @@ -17,11 +19,17 @@ class ShenandoahObjectCountClosure { } public: - ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} + ShenandoahObjectCountClosure() { initialize_table(); } // Record the object's instance in the KlassInfoTable inline void do_oop(narrowOop* o) { do_oop_work(o); } // Record the object's instance in the KlassInfoTable inline void do_oop(oop* o) { do_oop_work(o); } + inline KlassInfoTable* get_table() { return _cit; } + + void merge_tables(KlassInfoTable* main_cit); + +private: + void initialize_table(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 4545f9cc073da..211ce7de25ea5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -127,9 +127,10 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { bool object_count = ObjectCountEventSender::should_send_event(); if (object_count) { KlassInfoTable* _cit = ShenandoahHeap::heap()->get_cit(); - ShenandoahObjectCountClosure _count(_cit); + ShenandoahObjectCountClosure _count; ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); _root_scanner.roots_do(&init_mark, worker_id); + _count.merge_tables(_cit); } else { ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); _root_scanner.roots_do(&init_mark, worker_id); diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index fbfc14b7d5b03..3350104ceaf6a 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -179,7 +179,7 @@ void KlassInfoBucket::remove_from_list(KlassInfoEntry*& entry) { entry = nullptr; } - assert(entry == nullptr, "Entry should be deleted"); + assert(entry == nullptr, "Entry was not deleted"); } class KlassInfoTable::AllClassesFinder : public LockedClassesDo { @@ -244,10 +244,9 @@ bool KlassInfoTable::record_instance(const oop obj) { // elt may be null if it's a new klass for which we // could not allocate space for a new entry in the hashtable. if (elt != nullptr) { - elt->atomic_inc_count(); - size_t obj_size = obj->size(); - elt->atomic_add_words(obj_size); - Atomic::add(&_size_of_instances_in_words, obj_size); + elt->set_count(elt->count() + 1); + elt->set_words(elt->words() + obj->size()); + _size_of_instances_in_words += obj->size(); return true; } else { return false; diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index fb6a3827bc82b..6d42dc70e00f3 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -30,7 +30,6 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" #include "oops/annotations.hpp" -#include "runtime/atomic.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; @@ -73,11 +72,8 @@ class KlassInfoEntry: public CHeapObj { Klass* klass() const { return _klass; } uint64_t count() const { return _instance_count; } void set_count(uint64_t ct) { _instance_count = ct; } - void atomic_inc_count() { Atomic::inc(&_instance_count); } - void atomic_add_count(uint64_t add) { Atomic::add(&_instance_count, add); } size_t words() const { return _instance_words; } void set_words(size_t wds) { _instance_words = wds; } - void atomic_add_words(size_t add) { Atomic::add(&_instance_words, add); } void set_index(int64_t index) { _index = index; } int64_t index() const { return _index; } GrowableArray* subclasses() const { return _subclasses; } From a1c2ae1dbc7797c20c7f7cbdc6ddd61321b3dc20 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 6 Aug 2025 18:28:17 +0000 Subject: [PATCH 072/104] Threads now have their own instance of a KlassInfoTable and merging prevents race conditions --- src/hotspot/share/gc/shared/gcTrace.cpp | 10 +++------- .../share/gc/shenandoah/shenandoahClosures.hpp | 2 ++ .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 ++ .../gc/shenandoah/shenandoahConcurrentMark.cpp | 17 ++++++++++------- .../gc/shenandoah/shenandoahControlThread.cpp | 6 ++++++ .../share/gc/shenandoah/shenandoahHeap.cpp | 7 ------- .../share/gc/shenandoah/shenandoahHeap.hpp | 3 ++- .../gc/shenandoah/shenandoahHeap.inline.hpp | 9 +++++++++ .../share/gc/shenandoah/shenandoahMark.cpp | 12 +++++++----- .../shenandoahObjectCountClosure.cpp | 18 +++++++++--------- .../shenandoahObjectCountClosure.hpp | 9 +++------ .../share/gc/shenandoah/shenandoahSTWMark.cpp | 12 +++++++----- 12 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index bc729f1adb4b1..2801abc790b93 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,7 +27,8 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "jfr/jfrEvents.hpp" @@ -37,9 +38,6 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" -#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" -#include "iostream" - bool GCTracer::should_report_cpu_time_event() const { return should_send_cpu_time_event(); @@ -113,10 +111,8 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { template void GCTracer::report_object_count(T* heap) { KlassInfoTable* cit = heap->get_cit(); - ShenandoahObjectCountClosure t; - KlassInfoTable* new_cit = t.get_table(); - if (cit == nullptr && !ObjectCountEventSender::should_send_event()) { + if (cit == nullptr || !ObjectCountEventSender::should_send_event()) { return; } ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 4fd27fe07067c..c94891ed02cbb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -74,6 +74,7 @@ class ShenandoahMarkRefsSuperClosure : public ShenandoahSuperClosure { protected: template + // Return true if object was not previously marked by another thread bool work(T *p); public: @@ -115,6 +116,7 @@ class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure template inline void do_oop_work(T* p) { // If the object was not previously marked, then it is considered newly marked and we record it's instance in the KlassInfoTable + // Avoids double counting the same object bool newly_marked = work(p); if (newly_marked) { _count->do_oop(p); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index ea406a2313905..603f9215d5524 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -316,6 +316,8 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { heap->try_inject_alloc_failure(); VM_ShenandoahFinalMarkStartEvac op(this); VMThread::execute(&op); // jump to entry_final_mark under safepoint + + // Do not report object count during a safepoint assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); heap->tracer()->report_object_count(heap); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 814e7425a0745..82cff9494772d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -173,16 +173,19 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id); ShenandoahObjToScanQueue* old_q = (_old_queue_set == nullptr) ? nullptr : _old_queue_set->queue(worker_id); - bool object_count = ObjectCountEventSender::should_send_event(); - if (object_count) { - KlassInfoTable* _cit = ShenandoahHeap::heap()->get_cit(); - ShenandoahObjectCountClosure _count; + + // Use object counting closure if ObjectCountAfterGC event is enabled + bool object_count_enabled = ObjectCountEventSender::should_send_event(); + if (object_count_enabled) { + KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable local_cit(false); + ShenandoahObjectCountClosure _count(&local_cit); ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); _root_scanner.roots_do(&cl, worker_id); - _count.merge_tables(_cit); + _count.merge_tables(main_cit); } else { - ShenandoahMarkRefsClosure cl(q, _rp, old_q); - _root_scanner.roots_do(&cl, worker_id); + ShenandoahMarkRefsClosure cl(q, _rp, old_q); + _root_scanner.roots_do(&cl, worker_id); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 0c80b800ac5c3..d99835ef29aff 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -57,6 +57,12 @@ void ShenandoahControlThread::run_service() { ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); ShenandoahHeuristics* const heuristics = heap->heuristics(); + + // KlassInfoTable is a StackObj that shouldn't be heap-allocated. + // Use a static instance in the control thread to persist through GC cycles. + static KlassInfoTable temp_cit(false); + heap->set_cit(&temp_cit); + while (!should_terminate()) { const GCCause::Cause cancelled_cause = heap->cancelled_cause(); if (cancelled_cause == GCCause::_shenandoah_stop_vm) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index dadf3dc4775e9..399fae627fa97 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -687,9 +687,6 @@ void ShenandoahHeap::post_initialize() { _safepoint_workers->set_initialize_gclab(); } - static KlassInfoTable cit(false); - _cit = &cit; - JFR_ONLY(ShenandoahJFRSupport::register_jfr_type_serializers();) } @@ -807,10 +804,6 @@ void ShenandoahHeap::set_soft_max_capacity(size_t v) { Atomic::store(&_soft_max_size, v); } -KlassInfoTable* ShenandoahHeap::get_cit() { - return _cit; -} - size_t ShenandoahHeap::min_capacity() const { return _minimum_size; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 6dccf5e219c43..9a81ff9aae35a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -253,7 +253,8 @@ class ShenandoahHeap : public CollectedHeap { size_t committed() const; void set_soft_max_capacity(size_t v); - KlassInfoTable* get_cit(); + inline KlassInfoTable* get_cit(); + inline void set_cit(KlassInfoTable* cit); // ---------- Periodic Tasks // diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index cf9d808f7ce8f..4d74437802f56 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -46,6 +46,7 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/shenandoahWorkGroup.hpp" +#include "memory/heapInspection.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" @@ -647,4 +648,12 @@ inline ShenandoahMarkingContext* ShenandoahHeap::marking_context() const { return _marking_context; } +inline void ShenandoahHeap::set_cit(KlassInfoTable* cit) { + _cit = cit; +} + +inline KlassInfoTable* ShenandoahHeap::get_cit() { + return _cit; +} + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAP_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index edf2267f891c0..2345c5dfe6a59 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -69,14 +69,16 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); } else { - bool object_count = ObjectCountEventSender::should_send_event(); - if (object_count) { - KlassInfoTable* _cit = heap->get_cit(); - ShenandoahObjectCountClosure _count; + // Use object counting closure if ObjectCountAfterGC event is enabled + bool object_count_enabled = ObjectCountEventSender::should_send_event(); + if (object_count_enabled) { + KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable local_cit(false); + ShenandoahObjectCountClosure _count(&local_cit); using Closure = ShenandoahMarkRefsAndCountClosure; Closure cl(q, rp, old_q, &_count); mark_loop_work(&cl, ld, w, t, req); - _count.merge_tables(_cit); + _count.merge_tables(main_cit); } else { using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp, old_q); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index a7a8f8d5707a6..5252ef031af91 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,20 +1,20 @@ #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" +#include "runtime/mutex.hpp" -thread_local KlassInfoTable* ShenandoahObjectCountClosure::_cit = nullptr; - -// Change the return type to be a boolean -void ShenandoahObjectCountClosure::initialize_table() { - if (_cit == nullptr) { - static thread_local KlassInfoTable temp_table(false); - _cit = &temp_table; +static Mutex* get_merge_mutex() { + static Mutex* _merge_mutex = nullptr; + if (_merge_mutex == nullptr) { + _merge_mutex = new Mutex(Mutex::safepoint, "ShenandoahObjectCountMerge"); } + return _merge_mutex; } void ShenandoahObjectCountClosure::merge_tables(KlassInfoTable* main_cit) { if (main_cit == nullptr || _cit == nullptr) { return; } - + + MutexLocker ml(get_merge_mutex()); bool success = main_cit->merge(_cit); assert(success, "Failed to merge thread-local table"); -} \ No newline at end of file +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index da7055feb0350..c835a1b896149 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -6,10 +6,9 @@ #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" - class ShenandoahObjectCountClosure { private: - static thread_local KlassInfoTable* _cit; + KlassInfoTable* _cit; template inline void do_oop_work(T* p) { @@ -19,17 +18,15 @@ class ShenandoahObjectCountClosure { } public: - ShenandoahObjectCountClosure() { initialize_table(); } + ShenandoahObjectCountClosure(KlassInfoTable* cit): _cit(cit) {} // Record the object's instance in the KlassInfoTable inline void do_oop(narrowOop* o) { do_oop_work(o); } // Record the object's instance in the KlassInfoTable inline void do_oop(oop* o) { do_oop_work(o); } inline KlassInfoTable* get_table() { return _cit; } + // Merges the heap's KlassInfoTable with the thread's KlassInfoTable void merge_tables(KlassInfoTable* main_cit); - -private: - void initialize_table(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 211ce7de25ea5..b6fee6cfe839e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -124,13 +124,15 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { case NON_GEN: { - bool object_count = ObjectCountEventSender::should_send_event(); - if (object_count) { - KlassInfoTable* _cit = ShenandoahHeap::heap()->get_cit(); - ShenandoahObjectCountClosure _count; + // Use object counting closure if ObjectCountAfterGC event is enabled + bool object_count_enabled = ObjectCountEventSender::should_send_event(); + if (object_count_enabled) { + KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable local_cit(false); + ShenandoahObjectCountClosure _count(&local_cit); ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); _root_scanner.roots_do(&init_mark, worker_id); - _count.merge_tables(_cit); + _count.merge_tables(main_cit); } else { ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); _root_scanner.roots_do(&init_mark, worker_id); From 546d746e9b0535cc5ae6f1635283308c68ffd6fc Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 6 Aug 2025 21:25:15 +0000 Subject: [PATCH 073/104] Removed unnecessary #include statements --- src/hotspot/share/gc/shared/gcTrace.cpp | 2 -- src/hotspot/share/gc/shared/objectCountEventSender.cpp | 1 - src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 2 -- 3 files changed, 5 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 2801abc790b93..30d2c2967763c 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,8 +27,6 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "jfr/jfrEvents.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index e36cda2c8434c..16bc203823253 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -22,7 +22,6 @@ * */ - #include "gc/shared/objectCountEventSender.hpp" bool ObjectCountEventSender::_should_send_requestable_event = false; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 603f9215d5524..12fe7f823ab78 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -28,7 +28,6 @@ #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" @@ -36,7 +35,6 @@ #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" From 61f67c8b8e54974e33679b5ad5cb14eed32893da Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 6 Aug 2025 21:43:41 +0000 Subject: [PATCH 074/104] fixup! Removed unnecessary #include statements --- src/hotspot/share/gc/shared/gcTrace.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 30d2c2967763c..e3decace2ace0 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,6 +27,7 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "jfr/jfrEvents.hpp" From 4b0a2f744f3caa1683ac7cef7ac4a556d3c38481 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Wed, 6 Aug 2025 23:39:12 +0000 Subject: [PATCH 075/104] Created gcTrace.inline.hpp and objectCountEventSender.inline.hpp for templated methods --- src/hotspot/share/gc/shared/gcTrace.cpp | 45 +--------------- .../share/gc/shared/gcTrace.inline.hpp | 54 +++++++++++++++++++ .../gc/shared/objectCountEventSender.cpp | 8 --- .../gc/shared/objectCountEventSender.hpp | 41 +------------- .../shared/objectCountEventSender.inline.hpp | 46 ++++++++++++++++ .../gc/shenandoah/shenandoahConcurrentGC.cpp | 1 + .../shenandoah/shenandoahConcurrentMark.cpp | 5 +- .../share/gc/shenandoah/shenandoahMark.cpp | 2 +- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 5 +- .../share/jfr/periodic/jfrPeriodic.cpp | 2 +- src/hotspot/share/memory/heapInspection.hpp | 1 + 11 files changed, 111 insertions(+), 99 deletions(-) create mode 100644 src/hotspot/share/gc/shared/gcTrace.inline.hpp create mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index e3decace2ace0..9ea62b59b5248 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/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shared/gcTrace.inline.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "jfr/jfrEvents.hpp" @@ -77,47 +77,6 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con #if INCLUDE_SERVICES -template -class ObjectCountEventSenderClosure : public KlassInfoClosure { - const double _size_threshold_percentage; - size_t _total_size_in_words; - const Ticks _timestamp; - KlassInfoTable* _cit; - - public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit) : - _size_threshold_percentage(ObjectCountCutOffPercent / 100), - _total_size_in_words(total_size_in_words), - _timestamp(timestamp), - _cit(cit) - {} - - virtual void do_cinfo(KlassInfoEntry* entry) { - if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _timestamp); - _cit->delete_entry(entry, &_total_size_in_words); - } - } - - private: - bool should_send_event(const KlassInfoEntry* entry) const { - double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; - return percentage_of_heap >= _size_threshold_percentage; - } -}; - -// Assumes that the get_cit is a member of the heap class -template -void GCTracer::report_object_count(T* heap) { - KlassInfoTable* cit = heap->get_cit(); - - if (cit == nullptr || !ObjectCountEventSender::should_send_event()) { - return; - } - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); - 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 (ObjectCountEventSender::should_send_event()) { @@ -206,5 +165,3 @@ void ParallelOldTracer::report_dense_prefix(void* dense_prefix) { void OldGCTracer::report_concurrent_mode_failure() { send_concurrent_mode_failure_event(); } - -template void GCTracer::report_object_count(ShenandoahHeap* heap); diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp new file mode 100644 index 0000000000000..26441aba6d5a4 --- /dev/null +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -0,0 +1,54 @@ +#ifndef SHARE_GC_SHARED_GCTRACE_INLINE_HPP +#define SHARE_GC_SHARED_GCTRACE_INLINE_HPP + +#include "gc/shared/gcTrace.hpp" +#include "gc/shared/objectCountEventSender.inline.hpp" +#include "jfr/jfrEvents.hpp" +#include "memory/heapInspection.hpp" +#include "utilities/macros.hpp" + +#if INCLUDE_SERVICES + +template +class ObjectCountEventSenderClosure : public KlassInfoClosure { + const double _size_threshold_percentage; + size_t _total_size_in_words; + const Ticks _timestamp; + KlassInfoTable* _cit; + + public: + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit) : + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words), + _timestamp(timestamp), + _cit(cit) + {} + + virtual void do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + ObjectCountEventSender::send(entry, _timestamp); + _cit->delete_entry(entry, &_total_size_in_words); + } + } + + private: + bool should_send_event(const KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap >= _size_threshold_percentage; + } +}; + +template +void GCTracer::report_object_count(T* heap) { + KlassInfoTable* cit = heap->get_cit(); + + if (cit == nullptr || !ObjectCountEventSender::should_send_event()) { + return; + } + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + cit->iterate(&event_sender); +} + +#endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_GCTRACE_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index 16bc203823253..5244ea3f9cc60 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -25,11 +25,3 @@ #include "gc/shared/objectCountEventSender.hpp" 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; -} diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 093a83e4b8cc1..0fb6fd781a6b5 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -43,8 +43,8 @@ class ObjectCountEventSender : public AllStatic { 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 inline void enable_requestable_event(); + static inline void disable_requestable_event(); template static void send(const KlassInfoEntry* entry, const Ticks& timestamp); @@ -53,43 +53,6 @@ class ObjectCountEventSender : public AllStatic { static bool should_send_event(); }; -template -bool ObjectCountEventSender::should_send_event() { -#if INCLUDE_JFR - return _should_send_requestable_event || Event::is_enabled(); -#else - return false; -#endif // INCLUDE_JFR -} - -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); - } -} - #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp new file mode 100644 index 0000000000000..e4b358d32575b --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -0,0 +1,46 @@ +#include "gc/shared/objectCountEventSender.hpp" + +inline void ObjectCountEventSender::enable_requestable_event() { + _should_send_requestable_event = true; +} + +inline void ObjectCountEventSender::disable_requestable_event() { + _should_send_requestable_event = false; +} + +template +bool ObjectCountEventSender::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || Event::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + +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); + } +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 12fe7f823ab78..dbd917e887358 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.inline.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 82cff9494772d..2623ecba372cc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -23,7 +23,7 @@ * */ - +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shared/satbMarkQueue.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" @@ -33,6 +33,7 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" @@ -44,8 +45,6 @@ #include "memory/resourceArea.hpp" #include "runtime/continuation.hpp" #include "runtime/threads.hpp" -#include "gc/shared/objectCountEventSender.hpp" -#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 2345c5dfe6a59..3b8dcc43d3759 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -24,7 +24,7 @@ */ -#include "gc/shared/objectCountEventSender.hpp" +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index b6fee6cfe839e..613e2f44edb76 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -24,7 +24,7 @@ */ - +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/workerThread.hpp" @@ -32,12 +32,11 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" #include "gc/shenandoah/shenandoahVerifier.hpp" -#include "gc/shared/objectCountEventSender.hpp" -#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" class ShenandoahSTWMarkTask : public WorkerTask { private: diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 0be1c32728c08..0bb3237a743c7 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/objectCountEventSender.inline.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 6d42dc70e00f3..5058e29a8dacc 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -30,6 +30,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" #include "oops/annotations.hpp" +#include "runtime/mutex.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; From 0817661a78e7fd54ea74fafce7621d4d64f8bfee Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 7 Aug 2025 00:03:27 +0000 Subject: [PATCH 076/104] Fix for requestable event not declared --- src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index e4b358d32575b..8aa49c77ee7dc 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -1,11 +1,11 @@ #include "gc/shared/objectCountEventSender.hpp" inline void ObjectCountEventSender::enable_requestable_event() { - _should_send_requestable_event = true; + ObjectCountEventSender::_should_send_requestable_event = true; } inline void ObjectCountEventSender::disable_requestable_event() { - _should_send_requestable_event = false; + ObjectCountEventSender::_should_send_requestable_event = false; } template From 10f31fc28838ed7cfc16e67ef738db624e1a030c Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 7 Aug 2025 00:24:24 +0000 Subject: [PATCH 077/104] added compiliation guards --- src/hotspot/share/gc/shared/objectCountEventSender.cpp | 4 ++++ src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index 5244ea3f9cc60..5056bbdabd447 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -24,4 +24,8 @@ #include "gc/shared/objectCountEventSender.hpp" +#if INCLUDE_SERVICES + bool ObjectCountEventSender::_should_send_requestable_event = false; + +#endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index 8aa49c77ee7dc..5df33498b0b49 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -1,5 +1,7 @@ #include "gc/shared/objectCountEventSender.hpp" +#if INCLUDE_SERVICES + inline void ObjectCountEventSender::enable_requestable_event() { ObjectCountEventSender::_should_send_requestable_event = true; } @@ -44,3 +46,5 @@ void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& time send_event_if_enabled(klass, count, total_size, timestamp); } } + +#endif // INCLUDE_SERVICES From c86dd4a2b1f95114adb59af2cb9d91c7c323ad9f Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Thu, 7 Aug 2025 18:01:09 +0000 Subject: [PATCH 078/104] General comments + Mutex for merging tables --- src/hotspot/share/gc/shared/gcTrace.hpp | 3 ++- .../share/gc/shared/objectCountEventSender.hpp | 2 +- .../shared/objectCountEventSender.inline.hpp | 5 +++++ .../share/gc/shenandoah/shenandoahClosures.hpp | 3 +-- .../share/gc/shenandoah/shenandoahHeap.hpp | 6 +++++- .../gc/shenandoah/shenandoahMark.inline.hpp | 18 ++++++++++-------- .../shenandoahObjectCountClosure.cpp | 12 +++++------- .../shenandoahObjectCountClosure.hpp | 7 +++++-- 8 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 38620c0674ce7..115b618795597 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -103,7 +103,8 @@ 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; - // Sends event data to the ObjectCountAfterGC event + + // Sends event data to the ObjectCount and/or ObjectCountAfterGC event template void report_object_count(T* heap) NOT_SERVICES_RETURN; diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 0fb6fd781a6b5..f1177dd424b85 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -25,9 +25,9 @@ #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP +#include "jfr/jfrEvents.hpp" #include "memory/allStatic.hpp" #include "memory/heapInspection.hpp" -#include "jfr/jfrEvents.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index 5df33498b0b49..d709326b92bc4 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -1,3 +1,6 @@ +#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP + #include "gc/shared/objectCountEventSender.hpp" #if INCLUDE_SERVICES @@ -48,3 +51,5 @@ void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& time } #endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index c94891ed02cbb..f7793f543af7b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -115,8 +115,7 @@ class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure template inline void do_oop_work(T* p) { - // If the object was not previously marked, then it is considered newly marked and we record it's instance in the KlassInfoTable - // Avoids double counting the same object + // Count newly marked strong references to avoid double counting bool newly_marked = work(p); if (newly_marked) { _count->do_oop(p); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index f896e81d6538f..c04176117d381 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -253,9 +253,13 @@ class ShenandoahHeap : public CollectedHeap { size_t committed() const; void set_soft_max_capacity(size_t v); - inline KlassInfoTable* get_cit(); + + // Create Shenandoah's KlassInfoTable inline void set_cit(KlassInfoTable* cit); + // Return Shenandoah's KlassInfoTable + inline KlassInfoTable* get_cit(); + // ---------- Periodic Tasks // public: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 5655025f78b46..eb7aabe393641 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -297,7 +297,7 @@ inline bool ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, // Note: This is a very hot code path, so the code should be conditional on GENERATION template // parameter where possible, in order to generate the most efficient code. - bool marked = false; + bool strongly_marked = false; T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); @@ -306,7 +306,7 @@ inline bool ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, shenandoah_assert_not_forwarded(p, obj); shenandoah_assert_not_in_cset_except(p, obj, heap->cancelled_gc()); if (in_generation(heap, obj)) { - marked = mark_ref(q, mark_context, weak, obj); + strongly_marked = mark_ref(q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); if (GENERATION == YOUNG && heap->is_in_old(p)) { // Mark card as dirty because remembered set scanning still finds interesting pointer. @@ -317,7 +317,7 @@ inline bool ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, } } else if (old_q != nullptr) { // Young mark, bootstrapping old_q or concurrent with old_q marking. - marked = mark_ref(old_q, mark_context, weak, obj); + strongly_marked = mark_ref(old_q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); } else if (GENERATION == OLD) { // Old mark, found a young pointer. @@ -327,7 +327,7 @@ inline bool ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, } } } - return marked; + return strongly_marked; } template<> @@ -344,18 +344,18 @@ template inline bool ShenandoahMark::mark_non_generational_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak) { oop o = RawAccess<>::oop_load(p); - bool marked = false; + bool strongly_marked = false; if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); shenandoah_assert_not_forwarded(p, obj); shenandoah_assert_not_in_cset_except(p, obj, ShenandoahHeap::heap()->cancelled_gc()); - marked = mark_ref(q, mark_context, weak, obj); + strongly_marked = mark_ref(q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); } - return marked; + return strongly_marked; } inline bool ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, @@ -363,16 +363,18 @@ inline bool ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, bool weak, oop obj) { bool skip_live = false; bool marked; + bool strongly_marked = false; if (weak) { marked = mark_context->mark_weak(obj); } else { marked = mark_context->mark_strong(obj, /* was_upgraded = */ skip_live); + strongly_marked = marked; } if (marked) { bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); assert(pushed, "overflow queue should always succeed pushing"); } - return marked; + return strongly_marked; } ShenandoahObjToScanQueueSet* ShenandoahMark::task_queues() const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index 5252ef031af91..697cc84c48a72 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,12 +1,9 @@ #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "runtime/mutex.hpp" -static Mutex* get_merge_mutex() { - static Mutex* _merge_mutex = nullptr; - if (_merge_mutex == nullptr) { - _merge_mutex = new Mutex(Mutex::safepoint, "ShenandoahObjectCountMerge"); - } - return _merge_mutex; +Mutex* ShenandoahObjectCountClosure::get_mutex() { + static Mutex mutex(Mutex::nosafepoint, "ShenandoahObjectCountMerge"); + return &mutex; } void ShenandoahObjectCountClosure::merge_tables(KlassInfoTable* main_cit) { @@ -14,7 +11,8 @@ void ShenandoahObjectCountClosure::merge_tables(KlassInfoTable* main_cit) { return; } - MutexLocker ml(get_merge_mutex()); + Mutex* mutex = get_mutex(); + MutexLocker x(mutex, Mutex::_no_safepoint_check_flag); bool success = main_cit->merge(_cit); assert(success, "Failed to merge thread-local table"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index c835a1b896149..bfae98d59e11e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -9,7 +9,7 @@ class ShenandoahObjectCountClosure { private: KlassInfoTable* _cit; - + template inline void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); @@ -18,7 +18,7 @@ class ShenandoahObjectCountClosure { } public: - ShenandoahObjectCountClosure(KlassInfoTable* cit): _cit(cit) {} + ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} // Record the object's instance in the KlassInfoTable inline void do_oop(narrowOop* o) { do_oop_work(o); } // Record the object's instance in the KlassInfoTable @@ -27,6 +27,9 @@ class ShenandoahObjectCountClosure { // Merges the heap's KlassInfoTable with the thread's KlassInfoTable void merge_tables(KlassInfoTable* main_cit); + +private: + Mutex* get_mutex(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP From 8a910e042f6729a30f8772e8e0451fa91e416ea8 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Fri, 8 Aug 2025 17:02:05 +0000 Subject: [PATCH 079/104] Safety checks --- .../share/gc/shenandoah/shenandoahControlThread.cpp | 9 +++++---- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 3 ++- .../share/gc/shenandoah/shenandoahHeap.inline.hpp | 4 ++++ .../share/gc/shenandoah/shenandoahObjectCountClosure.hpp | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index d99835ef29aff..27a7ff54f364c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -58,10 +58,9 @@ void ShenandoahControlThread::run_service() { ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); ShenandoahHeuristics* const heuristics = heap->heuristics(); - // KlassInfoTable is a StackObj that shouldn't be heap-allocated. - // Use a static instance in the control thread to persist through GC cycles. - static KlassInfoTable temp_cit(false); - heap->set_cit(&temp_cit); + // Create the KlassInfoTable for Shenandoah. + KlassInfoTable cit(false); + heap->set_cit(&cit); while (!should_terminate()) { const GCCause::Cause cancelled_cause = heap->cancelled_cause(); @@ -254,6 +253,8 @@ void ShenandoahControlThread::run_service() { } os::naked_short_sleep(sleep); } + + heap->set_cit(nullptr); } void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index c04176117d381..9ab28cf079295 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -254,7 +254,8 @@ class ShenandoahHeap : public CollectedHeap { void set_soft_max_capacity(size_t v); - // Create Shenandoah's KlassInfoTable + // Create Shenandoah's KlassInfoTable. + // Used for JFR object count event support. inline void set_cit(KlassInfoTable* cit); // Return Shenandoah's KlassInfoTable diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 4d74437802f56..94cdade6623fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -649,10 +649,14 @@ inline ShenandoahMarkingContext* ShenandoahHeap::marking_context() const { } inline void ShenandoahHeap::set_cit(KlassInfoTable* cit) { + assert((_cit == nullptr && cit != nullptr) || + (_cit != nullptr && cit == nullptr), + "Initialize once & clear once"); _cit = cit; } inline KlassInfoTable* ShenandoahHeap::get_cit() { + assert(_cit != nullptr, "Should be initialized"); return _cit; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index bfae98d59e11e..52b71ac529819 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -5,6 +5,7 @@ #include "oops/access.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" +#include "runtime/mutex.hpp" class ShenandoahObjectCountClosure { private: From f85b098ecec99bcda624dba333e2e0cc2d081911 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 11 Aug 2025 18:41:19 +0000 Subject: [PATCH 080/104] Fix assert error for genshen --- src/hotspot/share/gc/shared/gcTrace.inline.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index 26441aba6d5a4..b243c4f068bab 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -40,13 +40,16 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { template void GCTracer::report_object_count(T* heap) { + if (!ObjectCountEventSender::should_send_event()) { + return; + } + KlassInfoTable* cit = heap->get_cit(); - if (cit == nullptr || !ObjectCountEventSender::should_send_event()) { - return; + if (!cit->allocation_failed()) { + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + cit->iterate(&event_sender); } - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); - cit->iterate(&event_sender); } #endif // INCLUDE_SERVICES From ec0c7c00bd372acb6bf267f83648f7151a20d52a Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Sat, 23 Aug 2025 23:01:14 +0000 Subject: [PATCH 081/104] Remove templates for should_send_event + Restructured logic for reporting object count --- src/hotspot/share/gc/shared/gcTrace.cpp | 4 ++-- src/hotspot/share/gc/shared/gcTrace.hpp | 4 ++-- .../share/gc/shared/gcTrace.inline.hpp | 24 ++++++++++++------- .../gc/shared/objectCountEventSender.cpp | 8 +++++++ .../gc/shared/objectCountEventSender.hpp | 1 - .../shared/objectCountEventSender.inline.hpp | 17 ++++--------- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 5 +++- .../shenandoah/shenandoahConcurrentMark.cpp | 2 +- .../share/gc/shenandoah/shenandoahMark.cpp | 2 +- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 8 ++++--- src/hotspot/share/memory/heapInspection.hpp | 6 ++++- .../gc/objectcount/ObjectCountEvent.java | 5 ---- 13 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 9ea62b59b5248..36e3c0992df50 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -79,14 +79,14 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con 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 (ObjectCountEventSender::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(), &cit); + 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 115b618795597..c087b891cc5bc 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -105,8 +105,8 @@ class GCTracer { void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; // Sends event data to the ObjectCount and/or ObjectCountAfterGC event - template - void report_object_count(T* heap) NOT_SERVICES_RETURN; + template + void report_object_count() NOT_SERVICES_RETURN; void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; void report_cpu_time_event(double user_time, double system_time, double real_time) const; diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index b243c4f068bab..06820f6d49791 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -9,7 +9,7 @@ #if INCLUDE_SERVICES -template +template class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; size_t _total_size_in_words; @@ -17,17 +17,23 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { KlassInfoTable* _cit; public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit) : + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit=nullptr) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), _timestamp(timestamp), _cit(cit) {} - + virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { ObjectCountEventSender::send(entry, _timestamp); - _cit->delete_entry(entry, &_total_size_in_words); + } + + // If the same KlassInfoTable is being used for every event emission, + // delete the entry even if we don't send it. This ensure live objects that + // weren't sent in a previous event emission are not monotonically increasing. + if (ShouldDelete) { + _cit->delete_entry(entry); } } @@ -38,17 +44,19 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -template -void GCTracer::report_object_count(T* heap) { - if (!ObjectCountEventSender::should_send_event()) { +template +void GCTracer::report_object_count() { + if (!ObjectCountEventSender::should_send_event()) { return; } + T* heap = T::heap(); KlassInfoTable* cit = heap->get_cit(); if (!cit->allocation_failed()) { - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); + cit->reset_size_of_instances_in_words(); } } diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index 5056bbdabd447..41f57b767eac6 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -28,4 +28,12 @@ bool ObjectCountEventSender::_should_send_requestable_event = false; +bool ObjectCountEventSender::should_send_event() { +#if INCLUDE_JFR + return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); +#else + return false; +#endif // INCLUDE_JFR +} + #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index f1177dd424b85..5a8a3f61cfbec 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -49,7 +49,6 @@ class ObjectCountEventSender : public AllStatic { template static void send(const KlassInfoEntry* entry, const Ticks& timestamp); - template static bool should_send_event(); }; diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index d709326b92bc4..d9a282862bd56 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -13,15 +13,6 @@ inline void ObjectCountEventSender::disable_requestable_event() { ObjectCountEventSender::_should_send_requestable_event = false; } -template -bool ObjectCountEventSender::should_send_event() { -#if INCLUDE_JFR - return _should_send_requestable_event || Event::is_enabled(); -#else - return false; -#endif // INCLUDE_JFR -} - template void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp) { T event(UNTIMED); @@ -43,9 +34,11 @@ void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& time 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()) { + + // If sending ObjectCountAfterGCEvent and ObjectCountEvent is enabled, + // Then we should emit data to both of these events. + // If sending ObjectCountEvent, do not send send ObjectCountAfterGCEvent. + if (std::is_same::value) { send_event_if_enabled(klass, count, total_size, timestamp); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index dbd917e887358..445488b23e8f5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -318,7 +318,10 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { // Do not report object count during a safepoint assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); - heap->tracer()->report_object_count(heap); + + #if INCLUDE_JFR + heap->tracer()->report_object_count(); + #endif // INCLUDE_JFR } void ShenandoahConcurrentGC::vmop_entry_init_update_refs() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 2623ecba372cc..3aaf3c7177003 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -174,7 +174,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { nullptr : _old_queue_set->queue(worker_id); // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event(); + const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 3b8dcc43d3759..cbabf40260e56 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -70,7 +70,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe mark_loop_work(&cl, ld, w, t, req); } else { // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event(); + const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 613e2f44edb76..e38a762fbd885 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -124,7 +124,7 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { switch (_generation->type()) { case NON_GEN: { // Use object counting closure if ObjectCountAfterGC event is enabled - bool object_count_enabled = ObjectCountEventSender::should_send_event(); + const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 3350104ceaf6a..d728b85640f0e 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -280,11 +280,13 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { return false; } -void KlassInfoTable::delete_entry(KlassInfoEntry* entry, size_t* total_table_size) { +void KlassInfoTable::reset_size_of_instances_in_words() { + _size_of_instances_in_words = 0; +} + +void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { uint idx = hash(entry->klass()) % _num_buckets; - size_t total_entry_size = entry->words(); _buckets[idx].remove_from_list(entry); - *total_table_size -= total_entry_size; } class KlassInfoTableMergeClosure : public KlassInfoClosure { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 5058e29a8dacc..3371bef0a0393 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -132,7 +132,11 @@ class KlassInfoTable: public StackObj { bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); // Deletes the KlassInfoEntry in the list - void delete_entry(KlassInfoEntry* entry, size_t* total_table_size); + void delete_entry(KlassInfoEntry* entry); + // Reset the size of instances in words to 0. Only call this method + // after sending the KlassInfoTable for the ObjectCount or + // ObjectCountAfterGC event and deleting it's entries. + void reset_size_of_instances_in_words(); friend class KlassInfoHisto; friend class KlassHierarchy; }; diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java index 30d9e141d8285..ea164370fa3e0 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/ObjectCountEvent.java @@ -25,14 +25,9 @@ public static void test(String gcName) throws Exception { ObjectCountEventVerifier.createTestData(); recording.start(); - - Path tempFile = Path.of("temp.jfr"); - recording.dump(tempFile); // Forces chunk rotation System.gc(); recording.stop(); - Files.deleteIfExists(tempFile); - System.out.println("gcName=" + gcName); List events = Events.fromRecording(recording); for (RecordedEvent event : events) { From 67ebc620d474c7f106400e720ca74f994a700aed Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Sun, 24 Aug 2025 04:20:29 +0000 Subject: [PATCH 082/104] Templatized ObjectCountEventSenderClosure class --- src/hotspot/share/gc/shared/gcTrace.cpp | 3 +-- src/hotspot/share/gc/shared/gcTrace.hpp | 4 +-- .../share/gc/shared/gcTrace.inline.hpp | 25 +++++++++++++------ .../gc/shared/objectCountEventSender.hpp | 2 +- .../shared/objectCountEventSender.inline.hpp | 16 ++++++------ .../gc/shenandoah/shenandoahConcurrentGC.cpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 10 +++++--- src/hotspot/share/memory/heapInspection.hpp | 8 +++--- 8 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 36e3c0992df50..32a93e2ed9a0e 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -30,7 +30,6 @@ #include "gc/shared/gcTrace.inline.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" -#include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" #include "runtime/os.hpp" @@ -86,7 +85,7 @@ 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); } } diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index c087b891cc5bc..abdd484a91c9c 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -104,8 +104,8 @@ class GCTracer { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; - // Sends event data to the ObjectCount and/or ObjectCountAfterGC event - template + // Sends event data to the ObjectCount and/or ObjectCountAfterGC event. + template void report_object_count() NOT_SERVICES_RETURN; void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index 06820f6d49791..19b45cdff49f2 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -3,13 +3,19 @@ #include "gc/shared/gcTrace.hpp" #include "gc/shared/objectCountEventSender.inline.hpp" -#include "jfr/jfrEvents.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #if INCLUDE_SERVICES -template +// The ObjectCountEventSenderClosure will decide whether to delete +// the entry and/or emit the ObjectCount and ObjectCountAfterGC +// events separately. Only set the delete entry flag to true if the same +// KlassInfoTable is being reused for this closure. The SeparateEventEmission +// determines if only the ObjectCount event will be emitted instead of +// ObjectCountAfterGC. If false, then both events will be emitted. + +template class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; size_t _total_size_in_words; @@ -26,13 +32,18 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { virtual void do_cinfo(KlassInfoEntry* entry) { if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _timestamp); + if (SeparateEventEmission) { + ObjectCountEventSender::send(entry, _timestamp); + } else { + ObjectCountEventSender::send(entry, _timestamp); + } } // If the same KlassInfoTable is being used for every event emission, // delete the entry even if we don't send it. This ensure live objects that // weren't sent in a previous event emission are not monotonically increasing. - if (ShouldDelete) { + if (DeleteEntry) { + assert(_cit != nullptr, "KlassInfoTable should be initialized"); _cit->delete_entry(entry); } } @@ -44,7 +55,7 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { } }; -template +template void GCTracer::report_object_count() { if (!ObjectCountEventSender::should_send_event()) { return; @@ -54,9 +65,9 @@ void GCTracer::report_object_count() { KlassInfoTable* cit = heap->get_cit(); if (!cit->allocation_failed()) { - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); - cit->reset_size_of_instances_in_words(); + assert(cit->size_of_instances_in_words() == 0, "KlassInfoTable should be empty"); } } diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 5a8a3f61cfbec..ed51c0be6cbe2 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -46,7 +46,7 @@ class ObjectCountEventSender : public AllStatic { static inline void enable_requestable_event(); static inline void disable_requestable_event(); - template + template static void send(const KlassInfoEntry* entry, const Ticks& timestamp); static bool should_send_event(); diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index d9a282862bd56..8d5b62176a2de 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -27,19 +27,21 @@ void ObjectCountEventSender::send_event_if_enabled(Klass* klass, jlong count, ju } } -template +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 and ObjectCountEvent is enabled, - // Then we should emit data to both of these events. - // If sending ObjectCountEvent, do not send send ObjectCountAfterGCEvent. - if (std::is_same::value) { + // If this request of object counting was done by the ObjectCount event, + // emit data for only that event and not ObjectCountAfterGC. We know + // that if this condition fails, then object counting was triggered by + // ObjectCountAfterGC. + if (SeparateEventEmission && _should_send_requestable_event) { + send_event_if_enabled(klass, count, total_size, timestamp); + } else { send_event_if_enabled(klass, count, total_size, timestamp); + send_event_if_enabled(klass, count, total_size, timestamp); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 445488b23e8f5..af59e30e7d4d1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -320,7 +320,7 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); #if INCLUDE_JFR - heap->tracer()->report_object_count(); + heap->tracer()->report_object_count(); #endif // INCLUDE_JFR } diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index d728b85640f0e..081ef554fbae1 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -264,6 +264,10 @@ size_t KlassInfoTable::size_of_instances_in_words() const { return _size_of_instances_in_words; } +void KlassInfoTable::subtract_total_size(size_t instance_words) { + _size_of_instances_in_words -= instance_words; +} + // Return false if the entry could not be recorded on account // of running out of space required to create a new entry. bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { @@ -280,13 +284,11 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { return false; } -void KlassInfoTable::reset_size_of_instances_in_words() { - _size_of_instances_in_words = 0; -} - void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { uint idx = hash(entry->klass()) % _num_buckets; + size_t words = entry->words(); _buckets[idx].remove_from_list(entry); + _size_of_instances_in_words -= words; } class KlassInfoTableMergeClosure : public KlassInfoClosure { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 3371bef0a0393..e8c5a291bd984 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -129,14 +129,12 @@ class KlassInfoTable: public StackObj { void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == nullptr; } size_t size_of_instances_in_words() const; + void subtract_total_size(size_t instance_words); bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); - // Deletes the KlassInfoEntry in the list + // Deletes the KlassInfoEntry and subtracts the total size + // of instances from the entry's size. void delete_entry(KlassInfoEntry* entry); - // Reset the size of instances in words to 0. Only call this method - // after sending the KlassInfoTable for the ObjectCount or - // ObjectCountAfterGC event and deleting it's entries. - void reset_size_of_instances_in_words(); friend class KlassInfoHisto; friend class KlassHierarchy; }; From bee4128e7398395cf171cc37d988cb2c4f883f81 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Sun, 24 Aug 2025 06:52:45 +0000 Subject: [PATCH 083/104] New lock called TableMerge_lock --- .../share/gc/shenandoah/shenandoahConcurrentMark.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 2 +- .../gc/shenandoah/shenandoahObjectCountClosure.cpp | 10 ++-------- .../gc/shenandoah/shenandoahObjectCountClosure.hpp | 3 --- src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp | 2 +- src/hotspot/share/runtime/mutexLocker.cpp | 2 ++ src/hotspot/share/runtime/mutexLocker.hpp | 1 + 7 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 3aaf3c7177003..95fcf27413f48 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -173,7 +173,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjToScanQueue* old_q = (_old_queue_set == nullptr) ? nullptr : _old_queue_set->queue(worker_id); - // Use object counting closure if ObjectCountAfterGC event is enabled + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index cbabf40260e56..8304348b94487 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -69,7 +69,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); } else { - // Use object counting closure if ObjectCountAfterGC event is enabled + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index 697cc84c48a72..887bb7e454460 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,18 +1,12 @@ #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" -#include "runtime/mutex.hpp" - -Mutex* ShenandoahObjectCountClosure::get_mutex() { - static Mutex mutex(Mutex::nosafepoint, "ShenandoahObjectCountMerge"); - return &mutex; -} +#include "runtime/mutexLocker.hpp" void ShenandoahObjectCountClosure::merge_tables(KlassInfoTable* main_cit) { if (main_cit == nullptr || _cit == nullptr) { return; } - Mutex* mutex = get_mutex(); - MutexLocker x(mutex, Mutex::_no_safepoint_check_flag); + MutexLocker x(TableMerge_lock, Mutex::_no_safepoint_check_flag); bool success = main_cit->merge(_cit); assert(success, "Failed to merge thread-local table"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index 52b71ac529819..10cb69cdad471 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -28,9 +28,6 @@ class ShenandoahObjectCountClosure { // Merges the heap's KlassInfoTable with the thread's KlassInfoTable void merge_tables(KlassInfoTable* main_cit); - -private: - Mutex* get_mutex(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index e38a762fbd885..d555d6ad4de6d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -123,7 +123,7 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { case NON_GEN: { - // Use object counting closure if ObjectCountAfterGC event is enabled + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 8cfecd098f616..494403598df76 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -85,6 +85,7 @@ Monitor* InitCompleted_lock = nullptr; Monitor* BeforeExit_lock = nullptr; Monitor* Notify_lock = nullptr; Mutex* ExceptionCache_lock = nullptr; +Mutex* TableMerge_lock = nullptr; Mutex* TrainingData_lock = nullptr; Monitor* TrainingReplayQueue_lock = nullptr; #ifndef PRODUCT @@ -246,6 +247,7 @@ void mutex_init() { MUTEX_DEFN(SignatureHandlerLibrary_lock , PaddedMutex , safepoint); MUTEX_DEFN(SymbolArena_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(ExceptionCache_lock , PaddedMutex , safepoint); + MUTEX_DEFN(TableMerge_lock , PaddedMutex , nosafepoint); #ifndef PRODUCT MUTEX_DEFN(FullGCALot_lock , PaddedMutex , safepoint); // a lock to make FullGCALot MT safe #endif diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f888c789eb738..9b7fef58ba0c4 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -87,6 +87,7 @@ extern Monitor* InitCompleted_lock; // a lock used to signal thread extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates +extern Mutex* TableMerge_lock; // a lock used to synchronize merging of thread-local KlassInfoTables #ifndef PRODUCT extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT safe From da8489781d6fbdcbe3df90209ceb74b6054e6637 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Sun, 24 Aug 2025 18:58:37 +0000 Subject: [PATCH 084/104] src/hotspot/share --- src/hotspot/share/gc/shared/gcTrace.cpp | 4 ++++ src/hotspot/share/gc/shared/gcTrace.inline.hpp | 13 ++++++++----- .../gc/shared/objectCountEventSender.inline.hpp | 2 +- .../share/gc/shenandoah/shenandoahClosures.hpp | 8 ++++---- .../gc/shenandoah/shenandoahConcurrentMark.cpp | 2 +- .../share/gc/shenandoah/shenandoahHeap.inline.hpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 2 +- .../gc/shenandoah/shenandoahObjectCountClosure.cpp | 8 +++++++- .../gc/shenandoah/shenandoahObjectCountClosure.hpp | 7 +++++-- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 2 +- src/hotspot/share/memory/heapInspection.cpp | 2 +- 11 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 32a93e2ed9a0e..034fae24dfecd 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -85,6 +85,10 @@ 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); + // Do not delete the KlassInfoTable's entry since it will be + // deconstructed automatically once it goes out of scope. + // No separate event emission is needed because both events + // will be sent together. ObjectCountEventSenderClosure event_sender(cit.size_of_instances_in_words(), Ticks::now()); cit.iterate(&event_sender); } diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index 19b45cdff49f2..59deda3087721 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -9,11 +9,11 @@ #if INCLUDE_SERVICES // The ObjectCountEventSenderClosure will decide whether to delete -// the entry and/or emit the ObjectCount and ObjectCountAfterGC -// events separately. Only set the delete entry flag to true if the same -// KlassInfoTable is being reused for this closure. The SeparateEventEmission -// determines if only the ObjectCount event will be emitted instead of -// ObjectCountAfterGC. If false, then both events will be emitted. +// the entry and/or emit the ObjectCount event separately. Only set +// the delete entry flag to true if the same KlassInfoTable is being +// reused for this closure. The SeparateEventEmissios determines if +// only the ObjectCount event will be emitted instead of ObjectCountAfterGC. +// If false, then both events will be emitted. template class ObjectCountEventSenderClosure : public KlassInfoClosure { @@ -65,6 +65,9 @@ void GCTracer::report_object_count() { KlassInfoTable* cit = heap->get_cit(); if (!cit->allocation_failed()) { + // Delete the entry of the KlassInfoTable since the table is local to the + // heap and will be reused again. Allow for separate event emission because + // to distinguish what event triggered this method. ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); cit->iterate(&event_sender); assert(cit->size_of_instances_in_words() == 0, "KlassInfoTable should be empty"); diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index 8d5b62176a2de..4d59f5bb75b52 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -36,7 +36,7 @@ void ObjectCountEventSender::send(const KlassInfoEntry* entry, const Ticks& time // If this request of object counting was done by the ObjectCount event, // emit data for only that event and not ObjectCountAfterGC. We know // that if this condition fails, then object counting was triggered by - // ObjectCountAfterGC. + // ObjectCountAfterGC and so emit both events. if (SeparateEventEmission && _should_send_requestable_event) { send_event_if_enabled(klass, count, total_size, timestamp); } else { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index f7793f543af7b..48a83e53d4bcc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -74,7 +74,7 @@ class ShenandoahMarkRefsSuperClosure : public ShenandoahSuperClosure { protected: template - // Return true if object was not previously marked by another thread + // Return true if object was not previously marked strong by another thread. bool work(T *p); public: @@ -115,9 +115,9 @@ class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure template inline void do_oop_work(T* p) { - // Count newly marked strong references to avoid double counting - bool newly_marked = work(p); - if (newly_marked) { + // Count newly marked strong references to avoid double counting. + bool newly_marked_strong = work(p); + if (newly_marked_strong) { _count->do_oop(p); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 95fcf27413f48..73fe53bb5b0d4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -181,7 +181,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjectCountClosure _count(&local_cit); ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); _root_scanner.roots_do(&cl, worker_id); - _count.merge_tables(main_cit); + _count.merge_table(main_cit); } else { ShenandoahMarkRefsClosure cl(q, _rp, old_q); _root_scanner.roots_do(&cl, worker_id); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 94cdade6623fb..7ca5da86d7f94 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -656,7 +656,7 @@ inline void ShenandoahHeap::set_cit(KlassInfoTable* cit) { } inline KlassInfoTable* ShenandoahHeap::get_cit() { - assert(_cit != nullptr, "Should be initialized"); + assert(_cit != nullptr, "KlassInfoTable for Shenandoah should be initialized"); return _cit; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 8304348b94487..e4ad71656c193 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -78,7 +78,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe using Closure = ShenandoahMarkRefsAndCountClosure; Closure cl(q, rp, old_q, &_count); mark_loop_work(&cl, ld, w, t, req); - _count.merge_tables(main_cit); + _count.merge_table(main_cit); } else { using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp, old_q); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index 887bb7e454460..de0421cae2f24 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,12 +1,18 @@ #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "runtime/mutexLocker.hpp" -void ShenandoahObjectCountClosure::merge_tables(KlassInfoTable* main_cit) { +void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* main_cit) { + assert(_cit != nullptr, "The thread-local KlassInfoTables are not initialized"); + assert(main_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); + if (main_cit == nullptr || _cit == nullptr) { return; } MutexLocker x(TableMerge_lock, Mutex::_no_safepoint_check_flag); bool success = main_cit->merge(_cit); + + // Clear the _cit in the closure to ensure it won't be used again. + _cit = nullptr; assert(success, "Failed to merge thread-local table"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index 10cb69cdad471..ae880bf86f79c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -14,6 +14,8 @@ class ShenandoahObjectCountClosure { template inline void do_oop_work(T* p) { T o = RawAccess<>::oop_load(p); + // No need to check if o is null because that was + // previously done by the marking. oop obj = CompressedOops::decode_not_null(o); _cit->record_instance(obj); } @@ -26,8 +28,9 @@ class ShenandoahObjectCountClosure { inline void do_oop(oop* o) { do_oop_work(o); } inline KlassInfoTable* get_table() { return _cit; } - // Merges the heap's KlassInfoTable with the thread's KlassInfoTable - void merge_tables(KlassInfoTable* main_cit); + // Merges the heap's KlassInfoTable with the thread's KlassInfoTable. + // Clears the thread's table, so it won't be used again. + void merge_table(KlassInfoTable* main_cit); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index d555d6ad4de6d..aeab12a540010 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -131,7 +131,7 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { ShenandoahObjectCountClosure _count(&local_cit); ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); _root_scanner.roots_do(&init_mark, worker_id); - _count.merge_tables(main_cit); + _count.merge_table(main_cit); } else { ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); _root_scanner.roots_do(&init_mark, worker_id); diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 081ef554fbae1..9ea652c777048 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -179,7 +179,7 @@ void KlassInfoBucket::remove_from_list(KlassInfoEntry*& entry) { entry = nullptr; } - assert(entry == nullptr, "Entry was not deleted"); + guarantee(false, "Entry not found."); } class KlassInfoTable::AllClassesFinder : public LockedClassesDo { From 729f4133abe06e6bd16aa95481e0dcc2980d9c5e Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 25 Aug 2025 17:10:12 +0000 Subject: [PATCH 085/104] Do not allow object counting for GenShen and only create cit if JFR is enabled. --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp | 3 --- src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 4 +++- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 766b15950cb37..b4377b11493d6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -318,10 +318,7 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { // Do not report object count during a safepoint assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); - - #if INCLUDE_JFR heap->tracer()->report_object_count(); - #endif // INCLUDE_JFR } void ShenandoahConcurrentGC::vmop_entry_init_update_refs() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 73fe53bb5b0d4..d01b2afa5d04a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -175,7 +175,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); - if (object_count_enabled) { + if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); ShenandoahObjectCountClosure _count(&local_cit); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 9015efb681932..eefd1ce8408a4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -58,9 +58,11 @@ void ShenandoahControlThread::run_service() { ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); ShenandoahHeuristics* const heuristics = heap->heuristics(); - // Create the KlassInfoTable for Shenandoah. + // Create the KlassInfoTable for Shenandoah only if JFR is enabled. + #if INCLUDE_JFR KlassInfoTable cit(false); heap->set_cit(&cit); + #endif // INCLUDE_JFR while (!should_terminate()) { const GCCause::Cause cancelled_cause = heap->cancelled_cause(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index e4ad71656c193..8fa9f0faa62f3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -71,7 +71,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe } else { // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); - if (object_count_enabled) { + if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); ShenandoahObjectCountClosure _count(&local_cit); From 2fa61d3e2eb9abe8528d5e61c828c04b3ab73543 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 25 Aug 2025 17:34:48 +0000 Subject: [PATCH 086/104] More documentation for method --- src/hotspot/share/gc/shared/objectCountEventSender.hpp | 3 +++ src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index ed51c0be6cbe2..2cdf51f366ec2 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -46,6 +46,9 @@ class ObjectCountEventSender : public AllStatic { static inline void enable_requestable_event(); static inline void disable_requestable_event(); + // Template parameter controls which JFR events are emitted: + // true = ObjectCount events only (when ObjectCount event initiated the request) + // false = Both ObjectCount and ObjectCountAfterGC events template static void send(const KlassInfoEntry* entry, const Ticks& timestamp); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index 9ab28cf079295..da11670f32693 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -258,7 +258,7 @@ class ShenandoahHeap : public CollectedHeap { // Used for JFR object count event support. inline void set_cit(KlassInfoTable* cit); - // Return Shenandoah's KlassInfoTable + // Return Shenandoah's KlassInfoTable. inline KlassInfoTable* get_cit(); // ---------- Periodic Tasks From 3d2bdeb109177f29665e7046845d7c6e927ad9e4 Mon Sep 17 00:00:00 2001 From: Patrick Fontanilla Date: Mon, 25 Aug 2025 23:42:48 +0000 Subject: [PATCH 087/104] Stronger assertion for ShenandoahObjectCountClosure --- .../share/gc/shenandoah/shenandoahConcurrentMark.cpp | 4 ++-- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 4 ++-- .../share/gc/shenandoah/shenandoahObjectCountClosure.cpp | 8 ++++---- .../share/gc/shenandoah/shenandoahObjectCountClosure.hpp | 7 ++++--- src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp | 4 ++-- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index d01b2afa5d04a..4befab5f6b84a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -176,12 +176,12 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { - KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); ShenandoahObjectCountClosure _count(&local_cit); ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); _root_scanner.roots_do(&cl, worker_id); - _count.merge_table(main_cit); + _count.merge_table(global_cit); } else { ShenandoahMarkRefsClosure cl(q, _rp, old_q); _root_scanner.roots_do(&cl, worker_id); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 8fa9f0faa62f3..562f9c1add60b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -72,13 +72,13 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { - KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); ShenandoahObjectCountClosure _count(&local_cit); using Closure = ShenandoahMarkRefsAndCountClosure; Closure cl(q, rp, old_q, &_count); mark_loop_work(&cl, ld, w, t, req); - _count.merge_table(main_cit); + _count.merge_table(global_cit); } else { using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp, old_q); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index de0421cae2f24..f897431300936 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,16 +1,16 @@ #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "runtime/mutexLocker.hpp" -void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* main_cit) { +void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { assert(_cit != nullptr, "The thread-local KlassInfoTables are not initialized"); - assert(main_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); + assert(global_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); - if (main_cit == nullptr || _cit == nullptr) { + if (global_cit == nullptr || _cit == nullptr) { return; } MutexLocker x(TableMerge_lock, Mutex::_no_safepoint_check_flag); - bool success = main_cit->merge(_cit); + bool success = global_cit->merge(_cit); // Clear the _cit in the closure to ensure it won't be used again. _cit = nullptr; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index ae880bf86f79c..f278075ba5576 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -13,10 +13,11 @@ class ShenandoahObjectCountClosure { template inline void do_oop_work(T* p) { + assert(p != nullptr, "Object is null."); T o = RawAccess<>::oop_load(p); - // No need to check if o is null because that was - // previously done by the marking. + assert(!CompressedOops::is_null(o), "CompressOops is null."); oop obj = CompressedOops::decode_not_null(o); + assert(_cit != nullptr, "KlassInfoTable is null."); _cit->record_instance(obj); } @@ -30,7 +31,7 @@ class ShenandoahObjectCountClosure { // Merges the heap's KlassInfoTable with the thread's KlassInfoTable. // Clears the thread's table, so it won't be used again. - void merge_table(KlassInfoTable* main_cit); + void merge_table(KlassInfoTable* global_cit); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index aeab12a540010..44a86cbca7a83 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -126,12 +126,12 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { - KlassInfoTable* const main_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); ShenandoahObjectCountClosure _count(&local_cit); ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); _root_scanner.roots_do(&init_mark, worker_id); - _count.merge_table(main_cit); + _count.merge_table(global_cit); } else { ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); _root_scanner.roots_do(&init_mark, worker_id); From 2c32f701f9c3541d32896b39bcbe072d4a6fa829 Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 26 Aug 2025 19:41:14 +0000 Subject: [PATCH 088/104] Don't reuse the same KlassInfoTable --- src/hotspot/share/gc/shared/gcTrace.cpp | 6 +-- .../share/gc/shared/gcTrace.inline.hpp | 28 ++++--------- .../gc/shenandoah/shenandoahClosures.hpp | 2 +- .../gc/shenandoah/shenandoahControlThread.cpp | 17 ++++---- .../gc/shenandoah/shenandoahHeap.inline.hpp | 3 +- src/hotspot/share/memory/heapInspection.cpp | 40 +------------------ src/hotspot/share/memory/heapInspection.hpp | 7 ---- 7 files changed, 19 insertions(+), 84 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 034fae24dfecd..0904ddbd27e3b 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -85,11 +85,7 @@ 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); - // Do not delete the KlassInfoTable's entry since it will be - // deconstructed automatically once it goes out of scope. - // No separate event emission is needed because both events - // will be sent together. - 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); } } diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index 59deda3087721..0e490af37e3f1 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -8,26 +8,21 @@ #if INCLUDE_SERVICES -// The ObjectCountEventSenderClosure will decide whether to delete -// the entry and/or emit the ObjectCount event separately. Only set -// the delete entry flag to true if the same KlassInfoTable is being -// reused for this closure. The SeparateEventEmissios determines if -// only the ObjectCount event will be emitted instead of ObjectCountAfterGC. -// If false, then both events will be emitted. +// The ObjectCountEventSenderClosure will determine if only the ObjectCount +// event will be emitted instead of ObjectCountAfterGC. If false, then both +// events will be emitted. -template +template class ObjectCountEventSenderClosure : public KlassInfoClosure { const double _size_threshold_percentage; size_t _total_size_in_words; const Ticks _timestamp; - KlassInfoTable* _cit; public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp, KlassInfoTable* cit=nullptr) : + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : _size_threshold_percentage(ObjectCountCutOffPercent / 100), _total_size_in_words(total_size_in_words), - _timestamp(timestamp), - _cit(cit) + _timestamp(timestamp) {} virtual void do_cinfo(KlassInfoEntry* entry) { @@ -38,14 +33,6 @@ class ObjectCountEventSenderClosure : public KlassInfoClosure { ObjectCountEventSender::send(entry, _timestamp); } } - - // If the same KlassInfoTable is being used for every event emission, - // delete the entry even if we don't send it. This ensure live objects that - // weren't sent in a previous event emission are not monotonically increasing. - if (DeleteEntry) { - assert(_cit != nullptr, "KlassInfoTable should be initialized"); - _cit->delete_entry(entry); - } } private: @@ -68,9 +55,8 @@ void GCTracer::report_object_count() { // Delete the entry of the KlassInfoTable since the table is local to the // heap and will be reused again. Allow for separate event emission because // to distinguish what event triggered this method. - ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now(), cit); + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); cit->iterate(&event_sender); - assert(cit->size_of_instances_in_words() == 0, "KlassInfoTable should be empty"); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 48a83e53d4bcc..52d3fd7e2727c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -116,7 +116,7 @@ class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure template inline void do_oop_work(T* p) { // Count newly marked strong references to avoid double counting. - bool newly_marked_strong = work(p); + const bool newly_marked_strong = work(p); if (newly_marked_strong) { _count->do_oop(p); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index eefd1ce8408a4..089a299715a68 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -57,13 +57,6 @@ void ShenandoahControlThread::run_service() { ShenandoahCollectorPolicy* const policy = heap->shenandoah_policy(); ShenandoahHeuristics* const heuristics = heap->heuristics(); - - // Create the KlassInfoTable for Shenandoah only if JFR is enabled. - #if INCLUDE_JFR - KlassInfoTable cit(false); - heap->set_cit(&cit); - #endif // INCLUDE_JFR - while (!should_terminate()) { const GCCause::Cause cancelled_cause = heap->cancelled_cause(); if (cancelled_cause == GCCause::_shenandoah_stop_vm) { @@ -132,6 +125,12 @@ void ShenandoahControlThread::run_service() { assert (!gc_requested || cause != GCCause::_last_gc_cause, "GC cause should be set"); if (gc_requested) { + // Create the KlassInfoTable for Shenandoah only if JFR is enabled. + #if INCLUDE_JFR + KlassInfoTable cit(false); + heap->set_cit(&cit); + #endif // INCLUDE_JFR + // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(heap); @@ -231,6 +230,8 @@ void ShenandoahControlThread::run_service() { // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); + + heap->set_cit(nullptr); } // Check if we have seen a new target for soft max heap size or if a gc was requested. @@ -255,8 +256,6 @@ void ShenandoahControlThread::run_service() { } os::naked_short_sleep(sleep); } - - heap->set_cit(nullptr); } void ShenandoahControlThread::service_concurrent_normal_cycle(GCCause::Cause cause) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 7ca5da86d7f94..234543e04d17d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -650,8 +650,7 @@ inline ShenandoahMarkingContext* ShenandoahHeap::marking_context() const { inline void ShenandoahHeap::set_cit(KlassInfoTable* cit) { assert((_cit == nullptr && cit != nullptr) || - (_cit != nullptr && cit == nullptr), - "Initialize once & clear once"); + (_cit != nullptr && cit == nullptr), "Initialize once & clear once"); _cit = cit; } diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 9ea652c777048..867ccc6106d8e 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -140,11 +140,8 @@ KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) { void KlassInfoBucket::iterate(KlassInfoClosure* cic) { KlassInfoEntry* elt = _list; while (elt != nullptr) { - // The remove_from_list method will delete elt if ObjectCountEventSenderClosure decides to send the event - // If the event is sent, we should save the next entry of the bucket and define elt as that next entry, since could be deleted - KlassInfoEntry* next = elt->next(); cic->do_cinfo(elt); - elt = next; + elt = elt->next(); } } @@ -158,30 +155,6 @@ void KlassInfoBucket::empty() { } } -void KlassInfoBucket::remove_from_list(KlassInfoEntry*& entry) { - if (_list == entry) { - KlassInfoEntry* next = _list->next(); - _list = next; - delete entry; - entry = nullptr; - return; - } - - KlassInfoEntry* current = _list; - while (current != nullptr && current->next() != entry) { - current = current->next(); - } - - if (current != nullptr && current->next() == entry) { - KlassInfoEntry* next = entry->next(); - current->set_next(next); - delete entry; - entry = nullptr; - } - - guarantee(false, "Entry not found."); -} - class KlassInfoTable::AllClassesFinder : public LockedClassesDo { KlassInfoTable *_table; public: @@ -264,10 +237,6 @@ size_t KlassInfoTable::size_of_instances_in_words() const { return _size_of_instances_in_words; } -void KlassInfoTable::subtract_total_size(size_t instance_words) { - _size_of_instances_in_words -= instance_words; -} - // Return false if the entry could not be recorded on account // of running out of space required to create a new entry. bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { @@ -284,13 +253,6 @@ bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) { return false; } -void KlassInfoTable::delete_entry(KlassInfoEntry* entry) { - uint idx = hash(entry->klass()) % _num_buckets; - size_t words = entry->words(); - _buckets[idx].remove_from_list(entry); - _size_of_instances_in_words -= words; -} - class KlassInfoTableMergeClosure : public KlassInfoClosure { private: KlassInfoTable* _dest; diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index e8c5a291bd984..b03806fcd7198 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -101,9 +101,6 @@ class KlassInfoBucket: public CHeapObj { KlassInfoEntry* lookup(Klass* k); void initialize() { _list = nullptr; } void empty(); - // Remove from the bucket list, and delete `entry`. - // `entry` must exist in the list. - void remove_from_list(KlassInfoEntry*& entry); void iterate(KlassInfoClosure* cic); }; @@ -129,12 +126,8 @@ class KlassInfoTable: public StackObj { void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == nullptr; } size_t size_of_instances_in_words() const; - void subtract_total_size(size_t instance_words); bool merge(KlassInfoTable* table); bool merge_entry(const KlassInfoEntry* cie); - // Deletes the KlassInfoEntry and subtracts the total size - // of instances from the entry's size. - void delete_entry(KlassInfoEntry* entry); friend class KlassInfoHisto; friend class KlassHierarchy; }; From 8b091f2382f19a331ab1e62255ebe13509cfcc76 Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 26 Aug 2025 20:02:54 +0000 Subject: [PATCH 089/104] Removed unused method in heapInspection.hpp --- src/hotspot/share/gc/shared/gcTrace.hpp | 4 +++- src/hotspot/share/gc/shared/gcTrace.inline.hpp | 5 ++--- .../share/gc/shenandoah/shenandoahObjectCountClosure.cpp | 6 +----- .../share/gc/shenandoah/shenandoahObjectCountClosure.hpp | 6 +++--- src/hotspot/share/memory/heapInspection.hpp | 1 - 5 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index abdd484a91c9c..13c308e3336eb 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -104,7 +104,9 @@ class GCTracer { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; - // Sends event data to the ObjectCount and/or ObjectCountAfterGC event. + // Report object count by not performing a heap inspection. This method will + // only work if there's a global KlassInfoTable that is already filled with + // entries prior to calling this method. template void report_object_count() NOT_SERVICES_RETURN; diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index 0e490af37e3f1..2a8d0fc3b9a0f 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -52,9 +52,8 @@ void GCTracer::report_object_count() { KlassInfoTable* cit = heap->get_cit(); if (!cit->allocation_failed()) { - // Delete the entry of the KlassInfoTable since the table is local to the - // heap and will be reused again. Allow for separate event emission because - // to distinguish what event triggered this method. + // Allow for separate event emission to distinguish if ObjectCount event + // triggered this method. ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); cit->iterate(&event_sender); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index f897431300936..6abfaa1a4b386 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -4,10 +4,6 @@ void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { assert(_cit != nullptr, "The thread-local KlassInfoTables are not initialized"); assert(global_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); - - if (global_cit == nullptr || _cit == nullptr) { - return; - } MutexLocker x(TableMerge_lock, Mutex::_no_safepoint_check_flag); bool success = global_cit->merge(_cit); @@ -15,4 +11,4 @@ void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { // Clear the _cit in the closure to ensure it won't be used again. _cit = nullptr; assert(success, "Failed to merge thread-local table"); -} +}∂ diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index f278075ba5576..692b2ac22cdd6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -13,11 +13,11 @@ class ShenandoahObjectCountClosure { template inline void do_oop_work(T* p) { - assert(p != nullptr, "Object is null."); + assert(p != nullptr, "Object is null"); T o = RawAccess<>::oop_load(p); - assert(!CompressedOops::is_null(o), "CompressOops is null."); + assert(!CompressedOops::is_null(o), "CompressOops is null"); oop obj = CompressedOops::decode_not_null(o); - assert(_cit != nullptr, "KlassInfoTable is null."); + assert(_cit != nullptr, "KlassInfoTable is null"); _cit->record_instance(obj); } diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index b03806fcd7198..06ef4f36598bd 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -67,7 +67,6 @@ class KlassInfoEntry: public CHeapObj { _do_print(false), _subclasses(nullptr) {} ~KlassInfoEntry(); - void set_next(KlassInfoEntry* next) { _next = next; } KlassInfoEntry* next() const { return _next; } bool is_equal(const Klass* k) { return k == _klass; } Klass* klass() const { return _klass; } From fce96de58f8e871cc2247e87deeb139a4f2573ba Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 26 Aug 2025 20:58:08 +0000 Subject: [PATCH 090/104] Accidentally pushed a char --- .../share/gc/shenandoah/shenandoahObjectCountClosure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index 6abfaa1a4b386..6cc76159ecfd1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -11,4 +11,4 @@ void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { // Clear the _cit in the closure to ensure it won't be used again. _cit = nullptr; assert(success, "Failed to merge thread-local table"); -}∂ +} From 0dd3c908e82f2cabc1c74fbb6f1f91b5c2447e72 Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 26 Aug 2025 22:47:59 +0000 Subject: [PATCH 091/104] Removed extra whitespace --- src/hotspot/share/memory/heapInspection.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 06ef4f36598bd..b9e9b5f9b28fd 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -126,6 +126,7 @@ class KlassInfoTable: public StackObj { bool allocation_failed() { return _buckets == nullptr; } size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); + bool merge_entry(const KlassInfoEntry* cie); friend class KlassInfoHisto; friend class KlassHierarchy; From b208281f95196f875f4c2af0cd31e15cbf7f3844 Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 26 Aug 2025 23:09:12 +0000 Subject: [PATCH 092/104] Reverted changes on master branch that were pushed accidentally --- .../TestObjectCountEventWithShenandoah.java | 17 --- test/lib/jdk/test/lib/jfr/GCHelper.java | 111 ++++++++---------- 2 files changed, 46 insertions(+), 82 deletions(-) delete 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 deleted file mode 100644 index 777230a16ab4a..0000000000000 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithShenandoah.java +++ /dev/null @@ -1,17 +0,0 @@ -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 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: Tue, 26 Aug 2025 23:13:01 +0000 Subject: [PATCH 093/104] Merged master + Removed unnecessary test files --- ...tObjectCountEventWithG1FullCollection.java | 22 ------------------- .../TestObjectCountEventWithParallelOld.java | 21 ------------------ 2 files changed, 43 deletions(-) delete mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java delete mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java deleted file mode 100644 index cd70c05239ccb..0000000000000 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithG1FullCollection.java +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 421c356a31579..0000000000000 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountEventWithParallelOld.java +++ /dev/null @@ -1,21 +0,0 @@ -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); - } -} From fbfe8b4d1b7f94f38bb02faef53d73e2e7c5d8fe Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 26 Aug 2025 23:24:18 +0000 Subject: [PATCH 094/104] Whitespace error --- src/hotspot/share/memory/heapInspection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index b9e9b5f9b28fd..1703aed0ef384 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -126,7 +126,7 @@ class KlassInfoTable: public StackObj { bool allocation_failed() { return _buckets == nullptr; } size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); - + bool merge_entry(const KlassInfoEntry* cie); friend class KlassInfoHisto; friend class KlassHierarchy; From ee8a1eb08a859f56894d0fe97b13e6efd5cb5703 Mon Sep 17 00:00:00 2001 From: pf0n Date: Thu, 28 Aug 2025 00:19:49 +0000 Subject: [PATCH 095/104] Fixed an inaccurate comment --- src/hotspot/share/gc/shared/gcTrace.hpp | 3 +-- ...ObjectCountAfterGCEventWithShenandoah.java | 23 ------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 13c308e3336eb..e5039955c82db 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -105,8 +105,7 @@ class GCTracer { void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; // Report object count by not performing a heap inspection. This method will - // only work if there's a global KlassInfoTable that is already filled with - // entries prior to calling this method. + // only work if there's a global KlassInfoTable in the heap. template void report_object_count() NOT_SERVICES_RETURN; diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java index d99bf8d536b97..42eef5b12f5d8 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java @@ -1,26 +1,3 @@ -/* - * 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. - */ - package jdk.jfr.event.gc.objectcount; import jdk.test.lib.jfr.GCHelper; From 508d0f26ef4de655630ac0608605d6fe2d67c862 Mon Sep 17 00:00:00 2001 From: pf0n Date: Thu, 28 Aug 2025 00:19:49 +0000 Subject: [PATCH 096/104] Fixed an inaccurate comment --- src/hotspot/share/gc/shared/gcTrace.hpp | 3 +- .../share/classes/java/io/Reader.java | 73 +++++++++++++++--- test/jdk/java/io/Reader/ReadAll.java | 75 ++++++++++++++++++- ...ObjectCountAfterGCEventWithShenandoah.java | 23 ------ .../bench/java/io/ReaderReadAllLines.java | 66 ++++++++++++++++ 5 files changed, 199 insertions(+), 41 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 13c308e3336eb..e5039955c82db 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -105,8 +105,7 @@ class GCTracer { void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; // Report object count by not performing a heap inspection. This method will - // only work if there's a global KlassInfoTable that is already filled with - // entries prior to calling this method. + // only work if there's a global KlassInfoTable in the heap. template void report_object_count() NOT_SERVICES_RETURN; diff --git a/src/java.base/share/classes/java/io/Reader.java b/src/java.base/share/classes/java/io/Reader.java index af5ac9f68ec7c..9656d14002337 100644 --- a/src/java.base/share/classes/java/io/Reader.java +++ b/src/java.base/share/classes/java/io/Reader.java @@ -27,8 +27,11 @@ import java.nio.CharBuffer; import java.nio.ReadOnlyBufferException; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; +import jdk.internal.util.ArraysSupport; /** * Abstract class for reading character streams. The only methods that a @@ -397,16 +400,6 @@ public int read(char[] cbuf) throws IOException { */ public abstract int read(char[] cbuf, int off, int len) throws IOException; - private String readAllCharsAsString() throws IOException { - StringBuilder result = new StringBuilder(); - char[] cbuf = new char[TRANSFER_BUFFER_SIZE]; - int nread; - while ((nread = read(cbuf, 0, cbuf.length)) != -1) { - result.append(cbuf, 0, nread); - } - return result.toString(); - } - /** * Reads all remaining characters as lines of text. This method blocks until * all remaining characters have been read and end of stream is detected, @@ -457,7 +450,57 @@ private String readAllCharsAsString() throws IOException { * @since 25 */ public List readAllLines() throws IOException { - return readAllCharsAsString().lines().toList(); + List lines = new ArrayList<>(); + char[] cb = new char[1024]; + + int start = 0; + int pos = 0; + int limit = 0; + boolean skipLF = false; + int n; + while ((n = read(cb, pos, cb.length - pos)) != -1) { + limit = pos + n; + while (pos < limit) { + if (skipLF) { + if (cb[pos] == '\n') { + pos++; + start++; + } + skipLF = false; + } + while (pos < limit) { + char c = cb[pos++]; + if (c == '\n' || c == '\r') { + lines.add(new String(cb, start, pos - 1 - start)); + skipLF = (c == '\r'); + start = pos; + break; + } + } + if (pos == limit) { + int len = limit - start; + if (len >= cb.length/2) { + // allocate larger buffer and copy chars to beginning + int newLength = ArraysSupport.newLength(cb.length, + TRANSFER_BUFFER_SIZE, cb.length); + char[] tmp = new char[newLength]; + System.arraycopy(cb, start, tmp, 0, len); + cb = tmp; + } else if (start != 0 && len != 0) { + // move fragment to beginning of buffer + System.arraycopy(cb, start, cb, 0, len); + } + pos = limit = len; + start = 0; + break; + } + } + } + // add a string if EOS terminates the last line + if (limit > start) + lines.add(new String(cb, start, limit - start)); + + return Collections.unmodifiableList(lines); } /** @@ -499,7 +542,13 @@ public List readAllLines() throws IOException { * @since 25 */ public String readAllAsString() throws IOException { - return readAllCharsAsString(); + StringBuilder result = new StringBuilder(); + char[] cbuf = new char[TRANSFER_BUFFER_SIZE]; + int nread; + while ((nread = read(cbuf, 0, cbuf.length)) != -1) { + result.append(cbuf, 0, nread); + } + return result.toString(); } /** Maximum skip-buffer size */ diff --git a/test/jdk/java/io/Reader/ReadAll.java b/test/jdk/java/io/Reader/ReadAll.java index 72fcf459eca77..fbe1d5a6431a0 100644 --- a/test/jdk/java/io/Reader/ReadAll.java +++ b/test/jdk/java/io/Reader/ReadAll.java @@ -66,12 +66,55 @@ public static void setup() throws IOException { int size = rnd.nextInt(2, 16386); int plen = PHRASE.length(); - List strings = new ArrayList(size); + StringBuilder sb = new StringBuilder(plen); + List strings = new ArrayList<>(size); while (strings.size() < size) { int fromIndex = rnd.nextInt(0, plen / 2); int toIndex = rnd.nextInt(fromIndex, plen); - strings.add(PHRASE.substring(fromIndex, toIndex)); + String s = PHRASE.substring(fromIndex, toIndex); + sb.append(s); + int bound = toIndex - fromIndex; + if (bound > 0) { + int offset = bound/2; + int n = rnd.nextInt(0, bound); + for (int i = 0; i < n; i++) { + String f = null; + switch (rnd.nextInt(7)) { + case 0 -> f = ""; + case 1 -> f = "\r"; + case 2 -> f = "\n"; + case 3 -> f = "\r\n"; + case 4 -> f = "\r\r"; + case 5 -> f = "\n\n"; + case 6 -> f = " "; + } + sb.insert(offset, f); + } + } + strings.add(sb.toString()); + sb.setLength(0); } + + String p4096 = PHRASE.repeat((4096 + plen - 1)/plen); + String p8192 = PHRASE.repeat((8192 + plen - 1)/plen); + String p16384 = PHRASE.repeat((16384 + plen - 1)/plen); + + for (int i = 0; i < 64; i++) { + for (int j = 0; j < 32; j++) { + switch (rnd.nextInt(8)) { + case 0 -> sb.append(""); + case 1 -> sb.append(" "); + case 2 -> sb.append("\n"); + case 3 -> sb.append(PHRASE); + case 5 -> sb.append(p4096); + case 6 -> sb.append(p8192); + case 7 -> sb.append(p16384); + } + } + strings.add(sb.toString()); + sb.setLength(0); + } + Files.write(path, strings); System.out.println(strings.size() + " lines written"); } @@ -85,6 +128,7 @@ public static void cleanup() throws IOException { @Test public void readAllLines() throws IOException { // Reader implementation + System.out.println("Reader implementation"); List lines; try (FileReader fr = new FileReader(file)) { lines = fr.readAllLines(); @@ -92,9 +136,21 @@ public void readAllLines() throws IOException { System.out.println(lines.size() + " lines read"); List linesExpected = Files.readAllLines(path); - assertEquals(linesExpected, lines); + int count = linesExpected.size(); + if (lines.size() != count) + throw new RuntimeException("Size mismatch: " + lines.size() + " != " + count); + for (int i = 0; i < count; i++) { + String expected = linesExpected.get(i); + String actual = lines.get(i); + if (!actual.equals(expected)) { + String msg = String.format("%d: \"%s\" != \"%s\"", + i, actual, expected); + throw new RuntimeException(msg); + } + } // Reader.of implementation + System.out.println("Reader.of implementation"); String stringExpected = Files.readString(path); int n = rnd.nextInt(stringExpected.length()/2); String substringExpected = stringExpected.substring(n); @@ -103,7 +159,18 @@ public void readAllLines() throws IOException { r.skip(n); lines = r.readAllLines(); } - assertEquals(linesExpected, lines); + count = linesExpected.size(); + if (lines.size() != count) + throw new RuntimeException("Size mismatch: " + lines.size() + " != " + count); + for (int i = 0; i < count; i++) { + String expected = linesExpected.get(i); + String actual = lines.get(i); + if (!actual.equals(expected)) { + String msg = String.format("%d: \"%s\" != \"%s\"", + i, actual, expected); + throw new RuntimeException(msg); + } + } } @Test diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java index d99bf8d536b97..42eef5b12f5d8 100644 --- a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java @@ -1,26 +1,3 @@ -/* - * 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. - */ - package jdk.jfr.event.gc.objectcount; import jdk.test.lib.jfr.GCHelper; diff --git a/test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java b/test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java new file mode 100644 index 0000000000000..a3663e083ec9b --- /dev/null +++ b/test/micro/org/openjdk/bench/java/io/ReaderReadAllLines.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 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. + */ +package org.openjdk.bench.java.io; + +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.Reader; +import java.util.List; +import java.util.Random; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +@State(Scope.Benchmark) +public class ReaderReadAllLines { + + private char[] chars = null; + + @Setup + public void setup() throws IOException { + final int len = 128_000; + chars = new char[len]; + Random rnd = new Random(System.nanoTime()); + int off = 0; + while (off < len) { + int lineLen = 40 + rnd.nextInt(8192); + if (lineLen > len - off) { + off = len; + } else { + chars[off + lineLen] = '\n'; + off += lineLen; + } + } + } + + @Benchmark + public List readAllLines() throws IOException { + List lines; + try (Reader reader = new CharArrayReader(chars)) { + lines = reader.readAllLines(); + } + return lines; + } +} From 1686fb3947fd49cd0c195ea87ab6ee02482eb80f Mon Sep 17 00:00:00 2001 From: pf0n Date: Thu, 28 Aug 2025 01:15:20 +0000 Subject: [PATCH 097/104] 8366122: Shenandoah: Implement efficient support for object count after gc events --- src/hotspot/share/gc/shared/gcTrace.cpp | 29 +-------- src/hotspot/share/gc/shared/gcTrace.hpp | 6 ++ .../share/gc/shared/gcTrace.inline.hpp | 62 +++++++++++++++++++ .../gc/shared/objectCountEventSender.cpp | 42 +------------ .../gc/shared/objectCountEventSender.hpp | 16 +++-- .../shared/objectCountEventSender.inline.hpp | 50 +++++++++++++++ .../gc/shenandoah/shenandoahClosures.hpp | 27 +++++++- .../shenandoah/shenandoahClosures.inline.hpp | 4 +- .../gc/shenandoah/shenandoahConcurrentGC.cpp | 4 ++ .../shenandoah/shenandoahConcurrentMark.cpp | 20 +++++- .../gc/shenandoah/shenandoahControlThread.cpp | 8 +++ .../share/gc/shenandoah/shenandoahHeap.cpp | 1 + .../share/gc/shenandoah/shenandoahHeap.hpp | 10 ++- .../gc/shenandoah/shenandoahHeap.inline.hpp | 12 ++++ .../share/gc/shenandoah/shenandoahMark.cpp | 20 ++++-- .../share/gc/shenandoah/shenandoahMark.hpp | 6 +- .../gc/shenandoah/shenandoahMark.inline.hpp | 27 +++++--- .../shenandoahObjectCountClosure.cpp | 13 ++++ .../shenandoahObjectCountClosure.hpp | 36 +++++++++++ .../share/gc/shenandoah/shenandoahSTWMark.cpp | 18 +++++- .../share/jfr/periodic/jfrPeriodic.cpp | 2 +- src/hotspot/share/memory/heapInspection.hpp | 3 +- src/hotspot/share/runtime/mutexLocker.cpp | 2 + src/hotspot/share/runtime/mutexLocker.hpp | 1 + ...ObjectCountAfterGCEventWithShenandoah.java | 17 +++++ test/lib/jdk/test/lib/jfr/GCHelper.java | 1 + 26 files changed, 338 insertions(+), 99 deletions(-) create mode 100644 src/hotspot/share/gc/shared/gcTrace.inline.hpp create mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp create mode 100644 test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index bad9c707b1e51..0904ddbd27e3b 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,6 +27,7 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" +#include "gc/shared/gcTrace.inline.hpp" #include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "memory/heapInspection.hpp" @@ -74,34 +75,9 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con } #if INCLUDE_SERVICES -class ObjectCountEventSenderClosure : public KlassInfoClosure { - const double _size_threshold_percentage; - const size_t _total_size_in_words; - const Ticks _timestamp; - - public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : - _size_threshold_percentage(ObjectCountCutOffPercent / 100), - _total_size_in_words(total_size_in_words), - _timestamp(timestamp) - {} - - virtual void do_cinfo(KlassInfoEntry* entry) { - if (should_send_event(entry)) { - ObjectCountEventSender::send(entry, _timestamp); - } - } - - private: - bool should_send_event(const KlassInfoEntry* entry) const { - double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; - return percentage_of_heap >= _size_threshold_percentage; - } -}; 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 (ObjectCountEventSender::should_send_event()) { ResourceMark rm; @@ -109,11 +85,12 @@ 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); } } } + #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index 6a47e54090f88..e5039955c82db 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -103,6 +103,12 @@ 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; + + // Report object count by not performing a heap inspection. This method will + // only work if there's a global KlassInfoTable in the heap. + template + void report_object_count() NOT_SERVICES_RETURN; + void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; void report_cpu_time_event(double user_time, double system_time, double real_time) const; diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp new file mode 100644 index 0000000000000..ba06eb00245d3 --- /dev/null +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -0,0 +1,62 @@ +#ifndef SHARE_GC_SHARED_GCTRACE_INLINE_HPP +#define SHARE_GC_SHARED_GCTRACE_INLINE_HPP + +#include "gc/shared/gcTrace.hpp" +#include "gc/shared/objectCountEventSender.inline.hpp" +#include "memory/heapInspection.hpp" +#include "utilities/macros.hpp" + +#if INCLUDE_SERVICES + +// The ObjectCountEventSenderClosure will determine if only the ObjectCount +// event will be emitted instead of ObjectCountAfterGC. If false, then both +// events will be emitted. + +template +class ObjectCountEventSenderClosure : public KlassInfoClosure { + const double _size_threshold_percentage; + size_t _total_size_in_words; + const Ticks _timestamp; + + public: + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words), + _timestamp(timestamp) + {} + virtual void do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + if (SeparateEventEmission) { + ObjectCountEventSender::send(entry, _timestamp); + } else { + ObjectCountEventSender::send(entry, _timestamp); + } + } + } + + private: + bool should_send_event(const KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap >= _size_threshold_percentage; + } +}; + +template +void GCTracer::report_object_count() { + if (!ObjectCountEventSender::should_send_event()) { + return; + } + T* heap = T::heap(); + KlassInfoTable* cit = heap->get_cit(); + + if (!cit->allocation_failed()) { + // Allow for separate event emission to distinguish if ObjectCount event + // triggered this method. + ObjectCountEventSenderClosure event_sender(cit->size_of_instances_in_words(), Ticks::now()); + cit->iterate(&event_sender); + } +} + +#endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_GCTRACE_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index a28c52e5c901d..41f57b767eac6 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -22,15 +22,12 @@ * */ - -#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_requestable_event = false; + bool ObjectCountEventSender::should_send_event() { #if INCLUDE_JFR return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); @@ -39,37 +36,4 @@ bool ObjectCountEventSender::should_send_event() { #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); - send_event_if_enabled(klass, count, total_size, timestamp); -} - #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 115fbfdaf7d3a..2cdf51f366ec2 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -25,12 +25,12 @@ #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP -#include "gc/shared/gcTrace.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/allStatic.hpp" +#include "memory/heapInspection.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" - #if INCLUDE_SERVICES class KlassInfoEntry; @@ -39,17 +39,23 @@ class Klass; class ObjectCountEventSender : public AllStatic { static bool _should_send_requestable_event; - template + 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 inline void enable_requestable_event(); + static inline void disable_requestable_event(); + // Template parameter controls which JFR events are emitted: + // true = ObjectCount events only (when ObjectCount event initiated the request) + // false = Both ObjectCount and ObjectCountAfterGC events + template 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.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp new file mode 100644 index 0000000000000..972a82b7cf362 --- /dev/null +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -0,0 +1,50 @@ +#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP +#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP + +#include "gc/shared/objectCountEventSender.hpp" + +#if INCLUDE_SERVICES + +inline void ObjectCountEventSender::enable_requestable_event() { + ObjectCountEventSender::_should_send_requestable_event = true; +} + +inline void ObjectCountEventSender::disable_requestable_event() { + ObjectCountEventSender::_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; + + // If this request of object counting was done by the ObjectCount event, + // emit data for only that event and not ObjectCountAfterGC. We know + // that if this condition fails, then object counting was triggered by + // ObjectCountAfterGC and so emit both events. + if (SeparateEventEmission && _should_send_requestable_event) { + send_event_if_enabled(klass, count, total_size, timestamp); + } else { + send_event_if_enabled(klass, count, total_size, timestamp); + send_event_if_enabled(klass, count, total_size, timestamp); + } +} + +#endif // INCLUDE_SERVICES + +#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index 0c223ee3128be..a161b365d7a53 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -27,6 +27,7 @@ #include "code/nmethod.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shenandoah/shenandoahTaskqueue.hpp" #include "memory/iterator.hpp" #include "runtime/javaThread.hpp" @@ -73,7 +74,8 @@ class ShenandoahMarkRefsSuperClosure : public ShenandoahSuperClosure { protected: template - void work(T *p); + // Return true if object was not previously marked strong by another thread. + bool work(T *p); public: inline ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp, ShenandoahObjToScanQueue* old_q); @@ -106,6 +108,29 @@ class ShenandoahMarkRefsClosure : public ShenandoahMarkRefsSuperClosure { virtual void do_oop(oop* p) { do_oop_work(p); } }; +#if INCLUDE_JFR +template +class ShenandoahMarkRefsAndCountClosure : public ShenandoahMarkRefsSuperClosure { +private: + ShenandoahObjectCountClosure* _count; + template + inline void do_oop_work(T* p) { + // Count newly marked strong references to avoid double counting. + const bool newly_marked_strong = work(p); + if (newly_marked_strong) { + _count->do_oop(p); + } + } + +public: + ShenandoahMarkRefsAndCountClosure(ShenandoahObjToScanQueue* q, ShenandoahReferenceProcessor* rp, ShenandoahObjToScanQueue* old_q, ShenandoahObjectCountClosure* count) : + ShenandoahMarkRefsSuperClosure(q, rp, old_q), _count(count) {}; + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop(oop* p) { do_oop_work(p); } +}; +#endif // INCLUDE_JFR + class ShenandoahForwardedIsAliveClosure : public BoolObjectClosure { private: ShenandoahMarkingContext* const _mark_context; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index 725e4e6e3e9f9..cf642f762b6f8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -77,8 +77,8 @@ ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToSc _weak(false) {} template -inline void ShenandoahMarkRefsSuperClosure::work(T* p) { - ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, _weak); +inline bool ShenandoahMarkRefsSuperClosure::work(T* p) { + return ShenandoahMark::mark_through_ref(p, _queue, _old_queue, _mark_context, _weak); } ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index d4c7ad5df50bf..e9ee01a14a55d 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.inline.hpp" #include "gc/shenandoah/shenandoahBreakpoint.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -314,6 +315,9 @@ void ShenandoahConcurrentGC::vmop_entry_final_mark() { heap->try_inject_alloc_failure(); VM_ShenandoahFinalMarkStartEvac op(this); VMThread::execute(&op); // jump to entry_final_mark under safepoint + // Do not report object count during a safepoint + assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should not be at safepoint"); + heap->tracer()->report_object_count(); } void ShenandoahConcurrentGC::vmop_entry_init_update_refs() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index facba2236be81..4befab5f6b84a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -23,7 +23,7 @@ * */ - +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shared/satbMarkQueue.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" @@ -33,6 +33,7 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" @@ -45,6 +46,7 @@ #include "runtime/continuation.hpp" #include "runtime/threads.hpp" + template class ShenandoahConcurrentMarkingTask : public WorkerTask { private: @@ -170,8 +172,20 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjToScanQueue* q = _queue_set->queue(worker_id); ShenandoahObjToScanQueue* old_q = (_old_queue_set == nullptr) ? nullptr : _old_queue_set->queue(worker_id); - ShenandoahMarkRefsClosure cl(q, _rp, old_q); - _root_scanner.roots_do(&cl, worker_id); + + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. + const bool object_count_enabled = ObjectCountEventSender::should_send_event(); + if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { + KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable local_cit(false); + ShenandoahObjectCountClosure _count(&local_cit); + ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); + _root_scanner.roots_do(&cl, worker_id); + _count.merge_table(global_cit); + } else { + ShenandoahMarkRefsClosure cl(q, _rp, old_q); + _root_scanner.roots_do(&cl, worker_id); + } } void ShenandoahConcurrentMark::mark_concurrent_roots() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 6290101bc49d4..089a299715a68 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -125,6 +125,12 @@ void ShenandoahControlThread::run_service() { assert (!gc_requested || cause != GCCause::_last_gc_cause, "GC cause should be set"); if (gc_requested) { + // Create the KlassInfoTable for Shenandoah only if JFR is enabled. + #if INCLUDE_JFR + KlassInfoTable cit(false); + heap->set_cit(&cit); + #endif // INCLUDE_JFR + // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(heap); @@ -224,6 +230,8 @@ void ShenandoahControlThread::run_service() { // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); + + heap->set_cit(nullptr); } // Check if we have seen a new target for soft max heap size or if a gc was requested. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index b90468501f67f..049b51a1d1f64 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -533,6 +533,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : _active_generation(nullptr), _initial_size(0), _committed(0), + _cit(nullptr), _max_workers(MAX3(ConcGCThreads, ParallelGCThreads, 1U)), _workers(nullptr), _safepoint_workers(nullptr), diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index bec1235e94140..f3da5efbbc61d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -43,6 +43,7 @@ #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" #include "gc/shenandoah/shenandoahUnload.hpp" +#include "memory/heapInspection.hpp" #include "memory/metaspace.hpp" #include "services/memoryManager.hpp" #include "utilities/globalDefinitions.hpp" @@ -228,7 +229,7 @@ class ShenandoahHeap : public CollectedHeap { shenandoah_padding(0); volatile size_t _committed; shenandoah_padding(1); - + KlassInfoTable* _cit; void increase_used(const ShenandoahAllocRequest& req); public: @@ -252,6 +253,13 @@ class ShenandoahHeap : public CollectedHeap { void set_soft_max_capacity(size_t v); + // Create Shenandoah's KlassInfoTable. + // Used for JFR object count event support. + inline void set_cit(KlassInfoTable* cit); + + // Return Shenandoah's KlassInfoTable. + inline KlassInfoTable* get_cit(); + // ---------- Periodic Tasks // public: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index cf9d808f7ce8f..234543e04d17d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -46,6 +46,7 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" #include "gc/shenandoah/shenandoahWorkGroup.hpp" +#include "memory/heapInspection.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" @@ -647,4 +648,15 @@ inline ShenandoahMarkingContext* ShenandoahHeap::marking_context() const { return _marking_context; } +inline void ShenandoahHeap::set_cit(KlassInfoTable* cit) { + assert((_cit == nullptr && cit != nullptr) || + (_cit != nullptr && cit == nullptr), "Initialize once & clear once"); + _cit = cit; +} + +inline KlassInfoTable* ShenandoahHeap::get_cit() { + assert(_cit != nullptr, "KlassInfoTable for Shenandoah should be initialized"); + return _cit; +} + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHHEAP_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 2a4149ee44dc4..562f9c1add60b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -24,7 +24,7 @@ */ - +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" @@ -69,9 +69,21 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); } else { - using Closure = ShenandoahMarkRefsClosure; - Closure cl(q, rp, old_q); - mark_loop_work(&cl, ld, w, t, req); + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. + const bool object_count_enabled = ObjectCountEventSender::should_send_event(); + if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { + KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable local_cit(false); + ShenandoahObjectCountClosure _count(&local_cit); + using Closure = ShenandoahMarkRefsAndCountClosure; + Closure cl(q, rp, old_q, &_count); + mark_loop_work(&cl, ld, w, t, req); + _count.merge_table(global_cit); + } else { + using Closure = ShenandoahMarkRefsClosure; + Closure cl(q, rp, old_q); + mark_loop_work(&cl, ld, w, t, req); + } } heap->flush_liveness_cache(w); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 4aef14f2c9aba..5675bfc3f5fa5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -57,7 +57,7 @@ class ShenandoahMark: public StackObj { public: template - static inline void mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak); + static inline bool mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak); // Loom support void start_mark(); @@ -99,9 +99,9 @@ class ShenandoahMark: public StackObj { static bool in_generation(ShenandoahHeap* const heap, oop obj); template - static void mark_non_generational_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak); + static bool mark_non_generational_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak); - static void mark_ref(ShenandoahObjToScanQueue* q, + static bool mark_ref(ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak, oop obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp index 2dc0813e51354..eb7aabe393641 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.inline.hpp @@ -293,10 +293,11 @@ bool ShenandoahMark::in_generation(ShenandoahHeap* const heap, oop obj) { } template -inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { +inline bool ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { // Note: This is a very hot code path, so the code should be conditional on GENERATION template // parameter where possible, in order to generate the most efficient code. + bool strongly_marked = false; T o = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); @@ -305,7 +306,7 @@ inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, shenandoah_assert_not_forwarded(p, obj); shenandoah_assert_not_in_cset_except(p, obj, heap->cancelled_gc()); if (in_generation(heap, obj)) { - mark_ref(q, mark_context, weak, obj); + strongly_marked = mark_ref(q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); if (GENERATION == YOUNG && heap->is_in_old(p)) { // Mark card as dirty because remembered set scanning still finds interesting pointer. @@ -316,7 +317,7 @@ inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, } } else if (old_q != nullptr) { // Young mark, bootstrapping old_q or concurrent with old_q marking. - mark_ref(old_q, mark_context, weak, obj); + strongly_marked = mark_ref(old_q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); } else if (GENERATION == OLD) { // Old mark, found a young pointer. @@ -326,48 +327,54 @@ inline void ShenandoahMark::mark_through_ref(T *p, ShenandoahObjToScanQueue* q, } } } + return strongly_marked; } template<> -inline void ShenandoahMark::mark_through_ref(oop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { - mark_non_generational_ref(p, q, mark_context, weak); +inline bool ShenandoahMark::mark_through_ref(oop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { + return mark_non_generational_ref(p, q, mark_context, weak); } template<> -inline void ShenandoahMark::mark_through_ref(narrowOop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { - mark_non_generational_ref(p, q, mark_context, weak); +inline bool ShenandoahMark::mark_through_ref(narrowOop *p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak) { + return mark_non_generational_ref(p, q, mark_context, weak); } template -inline void ShenandoahMark::mark_non_generational_ref(T* p, ShenandoahObjToScanQueue* q, +inline bool ShenandoahMark::mark_non_generational_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak) { oop o = RawAccess<>::oop_load(p); + bool strongly_marked = false; if (!CompressedOops::is_null(o)) { oop obj = CompressedOops::decode_not_null(o); shenandoah_assert_not_forwarded(p, obj); shenandoah_assert_not_in_cset_except(p, obj, ShenandoahHeap::heap()->cancelled_gc()); - mark_ref(q, mark_context, weak, obj); + strongly_marked = mark_ref(q, mark_context, weak, obj); shenandoah_assert_marked(p, obj); } + return strongly_marked; } -inline void ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, +inline bool ShenandoahMark::mark_ref(ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak, oop obj) { bool skip_live = false; bool marked; + bool strongly_marked = false; if (weak) { marked = mark_context->mark_weak(obj); } else { marked = mark_context->mark_strong(obj, /* was_upgraded = */ skip_live); + strongly_marked = marked; } if (marked) { bool pushed = q->push(ShenandoahMarkTask(obj, skip_live, weak)); assert(pushed, "overflow queue should always succeed pushing"); } + return strongly_marked; } ShenandoahObjToScanQueueSet* ShenandoahMark::task_queues() const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp new file mode 100644 index 0000000000000..f070dd764572b --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -0,0 +1,13 @@ +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" +#include "runtime/mutexLocker.hpp" + +void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { + assert(_cit != nullptr, "The thread-local KlassInfoTables are not initialized"); + assert(global_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); + MutexLocker x(TableMerge_lock, Mutex::_no_safepoint_check_flag); + bool success = global_cit->merge(_cit); + + // Clear the _cit in the closure to ensure it won't be used again. + _cit = nullptr; + assert(success, "Failed to merge thread-local table"); +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp new file mode 100644 index 0000000000000..941ff7a504577 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -0,0 +1,36 @@ +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP + +#include "memory/heapInspection.hpp" +#include "oops/access.hpp" +#include "oops/compressedOops.inline.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/mutex.hpp" + +class ShenandoahObjectCountClosure { +private: + KlassInfoTable* _cit; + template + inline void do_oop_work(T* p) { + assert(p != nullptr, "Object is null"); + T o = RawAccess<>::oop_load(p); + assert(!CompressedOops::is_null(o), "CompressOops is null"); + oop obj = CompressedOops::decode_not_null(o); + assert(_cit != nullptr, "KlassInfoTable is null"); + _cit->record_instance(obj); + } + +public: + ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} + // Record the object's instance in the KlassInfoTable + inline void do_oop(narrowOop* o) { do_oop_work(o); } + // Record the object's instance in the KlassInfoTable + inline void do_oop(oop* o) { do_oop_work(o); } + inline KlassInfoTable* get_table() { return _cit; } + + // Merges the heap's KlassInfoTable with the thread's KlassInfoTable. + // Clears the thread's table, so it won't be used again. + void merge_table(KlassInfoTable* global_cit); +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index c2bfea664fdcf..44a86cbca7a83 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -24,7 +24,7 @@ */ - +#include "gc/shared/objectCountEventSender.inline.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/workerThread.hpp" @@ -32,6 +32,7 @@ #include "gc/shenandoah/shenandoahGeneration.hpp" #include "gc/shenandoah/shenandoahGenerationType.hpp" #include "gc/shenandoah/shenandoahMark.inline.hpp" +#include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "gc/shenandoah/shenandoahReferenceProcessor.hpp" #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" #include "gc/shenandoah/shenandoahSTWMark.hpp" @@ -122,8 +123,19 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { case NON_GEN: { - ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); - _root_scanner.roots_do(&init_mark, worker_id); + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. + const bool object_count_enabled = ObjectCountEventSender::should_send_event(); + if (object_count_enabled) { + KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); + KlassInfoTable local_cit(false); + ShenandoahObjectCountClosure _count(&local_cit); + ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); + _root_scanner.roots_do(&init_mark, worker_id); + _count.merge_table(global_cit); + } else { + ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); + _root_scanner.roots_do(&init_mark, worker_id); + } break; } case GLOBAL: { diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 49669d1675ddc..13f32cc881ab1 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/objectCountEventSender.inline.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 58e91217a3223..20e4fb762bf7b 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -30,6 +30,7 @@ #include "oops/annotations.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" +#include "runtime/mutex.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; @@ -125,8 +126,8 @@ class KlassInfoTable: public StackObj { bool allocation_failed() { return _buckets == nullptr; } size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); - bool merge_entry(const KlassInfoEntry* cie); + bool merge_entry(const KlassInfoEntry* cie); friend class KlassInfoHisto; friend class KlassHierarchy; }; diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 8cfecd098f616..494403598df76 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -85,6 +85,7 @@ Monitor* InitCompleted_lock = nullptr; Monitor* BeforeExit_lock = nullptr; Monitor* Notify_lock = nullptr; Mutex* ExceptionCache_lock = nullptr; +Mutex* TableMerge_lock = nullptr; Mutex* TrainingData_lock = nullptr; Monitor* TrainingReplayQueue_lock = nullptr; #ifndef PRODUCT @@ -246,6 +247,7 @@ void mutex_init() { MUTEX_DEFN(SignatureHandlerLibrary_lock , PaddedMutex , safepoint); MUTEX_DEFN(SymbolArena_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(ExceptionCache_lock , PaddedMutex , safepoint); + MUTEX_DEFN(TableMerge_lock , PaddedMutex , nosafepoint); #ifndef PRODUCT MUTEX_DEFN(FullGCALot_lock , PaddedMutex , safepoint); // a lock to make FullGCALot MT safe #endif diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index f888c789eb738..9b7fef58ba0c4 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -87,6 +87,7 @@ extern Monitor* InitCompleted_lock; // a lock used to signal thread extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates +extern Mutex* TableMerge_lock; // a lock used to synchronize merging of thread-local KlassInfoTables #ifndef PRODUCT extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT safe diff --git a/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.java new file mode 100644 index 0000000000000..42eef5b12f5d8 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/objectcount/TestObjectCountAfterGCEventWithShenandoah.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 != true + * @library /test/lib /test/jdk + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps -XX:+UseShenandoahGC -XX:MarkSweepDeadRatio=0 -XX:-UseCompressedOops -XX:-UseCompressedClassPointers -XX:+IgnoreUnrecognizedVMOptions jdk.jfr.event.gc.objectcount.TestObjectCountAfterGCEventWithShenandoah + */ +public class TestObjectCountAfterGCEventWithShenandoah { + 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..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 87466a39ea0b638894a4c88377cb5b8875528814 Mon Sep 17 00:00:00 2001 From: pf0n Date: Thu, 28 Aug 2025 20:29:03 +0000 Subject: [PATCH 098/104] Compilation guards to reduce compile time for event --- .../share/gc/shenandoah/shenandoahConcurrentMark.cpp | 5 ++++- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 5 ++++- .../share/gc/shenandoah/shenandoahObjectCountClosure.cpp | 4 ++++ .../share/gc/shenandoah/shenandoahObjectCountClosure.hpp | 4 ++++ src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp | 7 +++++-- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 4befab5f6b84a..cb203266e1440 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -173,6 +173,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjToScanQueue* old_q = (_old_queue_set == nullptr) ? nullptr : _old_queue_set->queue(worker_id); + #if INCLUDE_JFR // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { @@ -182,7 +183,9 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); _root_scanner.roots_do(&cl, worker_id); _count.merge_table(global_cit); - } else { + } else + #endif // INCLUDE_JFR + { ShenandoahMarkRefsClosure cl(q, _rp, old_q); _root_scanner.roots_do(&cl, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 562f9c1add60b..c13de61e21ff2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -69,6 +69,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); } else { + #if INCLUDE_JFR // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { @@ -79,7 +80,9 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q, &_count); mark_loop_work(&cl, ld, w, t, req); _count.merge_table(global_cit); - } else { + } else + #endif // INCLUDE_JFR + { using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index f070dd764572b..61354cf1aef7f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,6 +1,8 @@ #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "runtime/mutexLocker.hpp" +#if INCLUDE_JFR + void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { assert(_cit != nullptr, "The thread-local KlassInfoTables are not initialized"); assert(global_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); @@ -11,3 +13,5 @@ void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { _cit = nullptr; assert(success, "Failed to merge thread-local table"); } + +#endif // INCLUDE_JFR diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index 941ff7a504577..e5559ce915afa 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -7,6 +7,8 @@ #include "oops/oop.inline.hpp" #include "runtime/mutex.hpp" +#if INCLUDE_JFR + class ShenandoahObjectCountClosure { private: KlassInfoTable* _cit; @@ -33,4 +35,6 @@ class ShenandoahObjectCountClosure { void merge_table(KlassInfoTable* global_cit); }; +#endif // INCLUDE_JFR + #endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJECTCOUNTCLOSURE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 44a86cbca7a83..494193bf7dd1b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -123,7 +123,8 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { case NON_GEN: { - // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. + #if INCLUDE_JFR + // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); @@ -132,7 +133,9 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); _root_scanner.roots_do(&init_mark, worker_id); _count.merge_table(global_cit); - } else { + } else + #endif // INCLUDE_JFR + { ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); _root_scanner.roots_do(&init_mark, worker_id); } From 0ce22eb6926edb46c48fb5b19a83b1777c3a2096 Mon Sep 17 00:00:00 2001 From: pf0n Date: Fri, 29 Aug 2025 23:04:47 +0000 Subject: [PATCH 099/104] Reverting changes back to original state for some files --- src/hotspot/share/gc/shared/gcTrace.cpp | 7 +- src/hotspot/share/gc/shared/gcTrace.hpp | 33 +++++++- .../share/gc/shared/gcTrace.inline.hpp | 41 +--------- .../gc/shared/objectCountEventSender.cpp | 41 +++++++++- .../gc/shared/objectCountEventSender.hpp | 14 +--- .../shared/objectCountEventSender.inline.hpp | 82 ++++++++----------- .../shenandoah/shenandoahConcurrentMark.cpp | 8 +- .../gc/shenandoah/shenandoahControlThread.cpp | 4 +- .../share/gc/shenandoah/shenandoahHeap.hpp | 6 +- .../gc/shenandoah/shenandoahHeap.inline.hpp | 6 +- .../share/gc/shenandoah/shenandoahMark.cpp | 6 +- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 6 +- .../share/jfr/periodic/jfrPeriodic.cpp | 2 +- src/hotspot/share/runtime/mutexLocker.hpp | 2 +- 14 files changed, 127 insertions(+), 131 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.cpp b/src/hotspot/share/gc/shared/gcTrace.cpp index 0904ddbd27e3b..a8d60d7d1799c 100644 --- a/src/hotspot/share/gc/shared/gcTrace.cpp +++ b/src/hotspot/share/gc/shared/gcTrace.cpp @@ -27,8 +27,6 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTrace.inline.hpp" -#include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/referenceProcessorStats.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" @@ -75,9 +73,9 @@ void GCTracer::report_gc_reference_stats(const ReferenceProcessorStats& rps) con } #if INCLUDE_SERVICES - 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 (ObjectCountEventSender::should_send_event()) { ResourceMark rm; @@ -85,12 +83,11 @@ 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); } } } - #endif // INCLUDE_SERVICES void GCTracer::report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const { diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index e5039955c82db..ce6927fa52aea 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -30,7 +30,9 @@ #include "gc/shared/gcId.hpp" #include "gc/shared/gcName.hpp" #include "gc/shared/gcWhen.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/workerThread.hpp" +#include "memory/heapInspection.hpp" #include "memory/metaspace.hpp" #include "memory/referenceType.hpp" #include "utilities/macros.hpp" @@ -92,6 +94,33 @@ class ParallelOldGCInfo { void* dense_prefix() const { return _dense_prefix; } }; +#if INCLUDE_SERVICES +class ObjectCountEventSenderClosure : public KlassInfoClosure { + const double _size_threshold_percentage; + const size_t _total_size_in_words; + const Ticks _timestamp; + + public: + ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words), + _timestamp(timestamp) + {} + + virtual void do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + ObjectCountEventSender::send(entry, _timestamp); + } + } + + private: + bool should_send_event(const KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap >= _size_threshold_percentage; + } +}; +#endif // INCLUDE_SERVICES + class GCTracer { protected: SharedGCInfo _shared_gc_info; @@ -103,13 +132,11 @@ class GCTracer { void report_gc_heap_summary(GCWhen::Type when, const GCHeapSummary& heap_summary) const; void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; - + void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; // Report object count by not performing a heap inspection. This method will // only work if there's a global KlassInfoTable in the heap. template void report_object_count() NOT_SERVICES_RETURN; - - void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; void report_cpu_time_event(double user_time, double system_time, double real_time) const; protected: diff --git a/src/hotspot/share/gc/shared/gcTrace.inline.hpp b/src/hotspot/share/gc/shared/gcTrace.inline.hpp index ba06eb00245d3..fa77bc55bc0d3 100644 --- a/src/hotspot/share/gc/shared/gcTrace.inline.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.inline.hpp @@ -2,61 +2,24 @@ #define SHARE_GC_SHARED_GCTRACE_INLINE_HPP #include "gc/shared/gcTrace.hpp" -#include "gc/shared/objectCountEventSender.inline.hpp" #include "memory/heapInspection.hpp" #include "utilities/macros.hpp" #if INCLUDE_SERVICES - -// The ObjectCountEventSenderClosure will determine if only the ObjectCount -// event will be emitted instead of ObjectCountAfterGC. If false, then both -// events will be emitted. - -template -class ObjectCountEventSenderClosure : public KlassInfoClosure { - const double _size_threshold_percentage; - size_t _total_size_in_words; - const Ticks _timestamp; - - public: - ObjectCountEventSenderClosure(size_t total_size_in_words, const Ticks& timestamp) : - _size_threshold_percentage(ObjectCountCutOffPercent / 100), - _total_size_in_words(total_size_in_words), - _timestamp(timestamp) - {} - virtual void do_cinfo(KlassInfoEntry* entry) { - if (should_send_event(entry)) { - if (SeparateEventEmission) { - ObjectCountEventSender::send(entry, _timestamp); - } else { - ObjectCountEventSender::send(entry, _timestamp); - } - } - } - - private: - bool should_send_event(const KlassInfoEntry* entry) const { - double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; - return percentage_of_heap >= _size_threshold_percentage; - } -}; - template void GCTracer::report_object_count() { if (!ObjectCountEventSender::should_send_event()) { return; } + T* heap = T::heap(); KlassInfoTable* cit = heap->get_cit(); if (!cit->allocation_failed()) { - // Allow for separate event emission to distinguish if ObjectCount event - // triggered this method. - 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); } } - #endif // INCLUDE_SERVICES #endif // SHARE_GC_SHARED_GCTRACE_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.cpp b/src/hotspot/share/gc/shared/objectCountEventSender.cpp index 41f57b767eac6..412428dc682b0 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.cpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.cpp @@ -22,12 +22,14 @@ * */ +#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_requestable_event = false; - bool ObjectCountEventSender::should_send_event() { #if INCLUDE_JFR return _should_send_requestable_event || EventObjectCountAfterGC::is_enabled(); @@ -36,4 +38,37 @@ bool ObjectCountEventSender::should_send_event() { #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); + send_event_if_enabled(klass, count, total_size, timestamp); +} + #endif // INCLUDE_SERVICES diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.hpp index 2cdf51f366ec2..25aeff5be5bda 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.hpp @@ -25,12 +25,12 @@ #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_HPP -#include "jfr/jfrEvents.hpp" #include "memory/allStatic.hpp" #include "memory/heapInspection.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ticks.hpp" + #if INCLUDE_SERVICES class KlassInfoEntry; @@ -39,23 +39,17 @@ class Klass; class ObjectCountEventSender : public AllStatic { static bool _should_send_requestable_event; - template + template static void send_event_if_enabled(Klass* klass, jlong count, julong size, const Ticks& timestamp); public: - static inline void enable_requestable_event(); - static inline void disable_requestable_event(); + static void enable_requestable_event(); + static void disable_requestable_event(); - // Template parameter controls which JFR events are emitted: - // true = ObjectCount events only (when ObjectCount event initiated the request) - // false = Both ObjectCount and ObjectCountAfterGC events - template 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.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp index 972a82b7cf362..60e8c431a5c8d 100644 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp @@ -1,50 +1,32 @@ -#ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP -#define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP - -#include "gc/shared/objectCountEventSender.hpp" - -#if INCLUDE_SERVICES - -inline void ObjectCountEventSender::enable_requestable_event() { - ObjectCountEventSender::_should_send_requestable_event = true; -} - -inline void ObjectCountEventSender::disable_requestable_event() { - ObjectCountEventSender::_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; - - // If this request of object counting was done by the ObjectCount event, - // emit data for only that event and not ObjectCountAfterGC. We know - // that if this condition fails, then object counting was triggered by - // ObjectCountAfterGC and so emit both events. - if (SeparateEventEmission && _should_send_requestable_event) { - send_event_if_enabled(klass, count, total_size, timestamp); - } else { - send_event_if_enabled(klass, count, total_size, timestamp); - send_event_if_enabled(klass, count, total_size, timestamp); - } -} - -#endif // INCLUDE_SERVICES - -#endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP +// #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP +// #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP + +// #include "gc/shared/objectCountEventSender.hpp" + +// #if INCLUDE_SERVICES + +// inline void ObjectCountEventSender::enable_requestable_event() { +// ObjectCountEventSender::_should_send_requestable_event = true; +// } + +// inline void ObjectCountEventSender::disable_requestable_event() { +// ObjectCountEventSender::_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(); +// } +// } + +// #endif // INCLUDE_SERVICES + +// #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index cb203266e1440..a71ac40ca012a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -23,7 +23,7 @@ * */ -#include "gc/shared/objectCountEventSender.inline.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/satbMarkQueue.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" @@ -173,10 +173,10 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { ShenandoahObjToScanQueue* old_q = (_old_queue_set == nullptr) ? nullptr : _old_queue_set->queue(worker_id); - #if INCLUDE_JFR +#if INCLUDE_JFR // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); - if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { + if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); ShenandoahObjectCountClosure _count(&local_cit); @@ -184,7 +184,7 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { _root_scanner.roots_do(&cl, worker_id); _count.merge_table(global_cit); } else - #endif // INCLUDE_JFR +#endif // INCLUDE_JFR { ShenandoahMarkRefsClosure cl(q, _rp, old_q); _root_scanner.roots_do(&cl, worker_id); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 089a299715a68..e073789e5100f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -126,10 +126,10 @@ void ShenandoahControlThread::run_service() { if (gc_requested) { // Create the KlassInfoTable for Shenandoah only if JFR is enabled. - #if INCLUDE_JFR +#if INCLUDE_JFR KlassInfoTable cit(false); heap->set_cit(&cit); - #endif // INCLUDE_JFR +#endif // INCLUDE_JFR // Cannot uncommit bitmap slices during concurrent reset ShenandoahNoUncommitMark forbid_region_uncommit(heap); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index f3da5efbbc61d..2fb1e74df024b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -229,6 +229,7 @@ class ShenandoahHeap : public CollectedHeap { shenandoah_padding(0); volatile size_t _committed; shenandoah_padding(1); + // Used for JFR object count event support. KlassInfoTable* _cit; void increase_used(const ShenandoahAllocRequest& req); @@ -253,11 +254,8 @@ class ShenandoahHeap : public CollectedHeap { void set_soft_max_capacity(size_t v); - // Create Shenandoah's KlassInfoTable. - // Used for JFR object count event support. + // Setter & accessor for class histogram inline void set_cit(KlassInfoTable* cit); - - // Return Shenandoah's KlassInfoTable. inline KlassInfoTable* get_cit(); // ---------- Periodic Tasks diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 234543e04d17d..7eb5bf8a195e6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -649,13 +649,13 @@ inline ShenandoahMarkingContext* ShenandoahHeap::marking_context() const { } inline void ShenandoahHeap::set_cit(KlassInfoTable* cit) { - assert((_cit == nullptr && cit != nullptr) || - (_cit != nullptr && cit == nullptr), "Initialize once & clear once"); + assert(_cit == nullptr || cit == nullptr, "Overwriting an existing histogram"); + assert(_cit != nullptr || cit != nullptr, "Already cleared"); _cit = cit; } inline KlassInfoTable* ShenandoahHeap::get_cit() { - assert(_cit != nullptr, "KlassInfoTable for Shenandoah should be initialized"); + assert(_cit != nullptr, "KlassInfoTable is null"); return _cit; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index c13de61e21ff2..53e8d94658859 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -24,7 +24,7 @@ */ -#include "gc/shared/objectCountEventSender.inline.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahGeneration.hpp" @@ -69,7 +69,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe Closure cl(q, rp, old_q); mark_loop_work(&cl, ld, w, t, req); } else { - #if INCLUDE_JFR +#if INCLUDE_JFR // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { @@ -81,7 +81,7 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe mark_loop_work(&cl, ld, w, t, req); _count.merge_table(global_cit); } else - #endif // INCLUDE_JFR +#endif // INCLUDE_JFR { using Closure = ShenandoahMarkRefsClosure; Closure cl(q, rp, old_q); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 494193bf7dd1b..876f67b7bd55f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -24,7 +24,7 @@ */ -#include "gc/shared/objectCountEventSender.inline.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "gc/shared/strongRootsScope.hpp" #include "gc/shared/taskTerminator.hpp" #include "gc/shared/workerThread.hpp" @@ -123,7 +123,7 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { auto queue = task_queues()->queue(worker_id); switch (_generation->type()) { case NON_GEN: { - #if INCLUDE_JFR +#if INCLUDE_JFR // Use object counting closure if ObjectCount or ObjectCountAfterGC event is enabled. const bool object_count_enabled = ObjectCountEventSender::should_send_event(); if (object_count_enabled) { @@ -134,7 +134,7 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { _root_scanner.roots_do(&init_mark, worker_id); _count.merge_table(global_cit); } else - #endif // INCLUDE_JFR +#endif // INCLUDE_JFR { ShenandoahMarkRefsClosure init_mark(queue, rp, nullptr); _root_scanner.roots_do(&init_mark, worker_id); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 13f32cc881ab1..49669d1675ddc 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.inline.hpp" +#include "gc/shared/objectCountEventSender.hpp" #include "jfr/jfrEvents.hpp" #include "jfr/periodic/jfrCompilerQueueUtilization.hpp" #include "jfr/periodic/jfrFinalizerStatisticsEvent.hpp" diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 9b7fef58ba0c4..87b483fa1bede 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -87,7 +87,7 @@ extern Monitor* InitCompleted_lock; // a lock used to signal thread extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates -extern Mutex* TableMerge_lock; // a lock used to synchronize merging of thread-local KlassInfoTables +extern Mutex* TableMerge_lock; // a lock used to synchronize merging a thread-local table into a global table #ifndef PRODUCT extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT safe From 668fdaed44975c9ac617611481fa09194f36d3a1 Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 2 Sep 2025 04:04:48 +0000 Subject: [PATCH 100/104] Deleted objectCountEventSender.inline.hpp --- .../shared/objectCountEventSender.inline.hpp | 32 ------------------- 1 file changed, 32 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp diff --git a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp b/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp deleted file mode 100644 index 60e8c431a5c8d..0000000000000 --- a/src/hotspot/share/gc/shared/objectCountEventSender.inline.hpp +++ /dev/null @@ -1,32 +0,0 @@ -// #ifndef SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP -// #define SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP - -// #include "gc/shared/objectCountEventSender.hpp" - -// #if INCLUDE_SERVICES - -// inline void ObjectCountEventSender::enable_requestable_event() { -// ObjectCountEventSender::_should_send_requestable_event = true; -// } - -// inline void ObjectCountEventSender::disable_requestable_event() { -// ObjectCountEventSender::_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(); -// } -// } - -// #endif // INCLUDE_SERVICES - -// #endif // SHARE_GC_SHARED_OBJECTCOUNTEVENTSENDER_INLINE_HPP From 68e21c198c737211600931d4477f93e43ff7e6dc Mon Sep 17 00:00:00 2001 From: pf0n Date: Tue, 2 Sep 2025 06:17:13 +0000 Subject: [PATCH 101/104] Comment on why return value was changed to bool --- src/hotspot/share/gc/shenandoah/shenandoahMark.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp index 5675bfc3f5fa5..d8526ac8f2f62 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.hpp @@ -56,6 +56,7 @@ class ShenandoahMark: public StackObj { ShenandoahMark(ShenandoahGeneration* generation); public: + // Returns true if object was strongly marked. template static inline bool mark_through_ref(T* p, ShenandoahObjToScanQueue* q, ShenandoahObjToScanQueue* old_q, ShenandoahMarkingContext* const mark_context, bool weak); @@ -98,9 +99,11 @@ class ShenandoahMark: public StackObj { template static bool in_generation(ShenandoahHeap* const heap, oop obj); + // Returns true if object was strongly marked. template static bool mark_non_generational_ref(T *p, ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak); + // Returns true if object was strongly marked. static bool mark_ref(ShenandoahObjToScanQueue* q, ShenandoahMarkingContext* const mark_context, bool weak, oop obj); From 11ef54f445ad7425be426b3dc85ae89c7f77174d Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 3 Sep 2025 03:32:28 +0000 Subject: [PATCH 102/104] Renamed variables, better comment, included guard, removed mutex header --- src/hotspot/share/gc/shared/gcTrace.hpp | 2 +- .../share/gc/shenandoah/shenandoahConcurrentMark.cpp | 6 +++--- src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp | 3 ++- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 6 +++--- .../share/gc/shenandoah/shenandoahObjectCountClosure.cpp | 4 ++-- src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp | 6 +++--- src/hotspot/share/memory/heapInspection.hpp | 3 +-- src/hotspot/share/runtime/mutexLocker.cpp | 4 ++-- src/hotspot/share/runtime/mutexLocker.hpp | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/hotspot/share/gc/shared/gcTrace.hpp b/src/hotspot/share/gc/shared/gcTrace.hpp index ce6927fa52aea..c137123535b11 100644 --- a/src/hotspot/share/gc/shared/gcTrace.hpp +++ b/src/hotspot/share/gc/shared/gcTrace.hpp @@ -133,7 +133,7 @@ class GCTracer { void report_metaspace_summary(GCWhen::Type when, const MetaspaceSummary& metaspace_summary) const; void report_gc_reference_stats(const ReferenceProcessorStats& rp) const; void report_object_count_after_gc(BoolObjectClosure* object_filter, WorkerThreads* workers) NOT_SERVICES_RETURN; - // Report object count by not performing a heap inspection. This method will + // Report object count without performing a heap inspection. This method will // only work if there's a global KlassInfoTable in the heap. template void report_object_count() NOT_SERVICES_RETURN; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index a71ac40ca012a..c43a71f2b59bb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -179,10 +179,10 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); - ShenandoahObjectCountClosure _count(&local_cit); - ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &_count); + ShenandoahObjectCountClosure count(&local_cit); + ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &count); _root_scanner.roots_do(&cl, worker_id); - _count.merge_table(global_cit); + count.merge_table(global_cit); } else #endif // INCLUDE_JFR { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index e073789e5100f..6d1efe7d8e5e2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -230,8 +230,9 @@ void ShenandoahControlThread::run_service() { // Print Metaspace change following GC (if logging is enabled). MetaspaceUtils::print_metaspace_change(meta_sizes); - +#if INCLUDE_JFR heap->set_cit(nullptr); +#endif // INCLUDE_JFR } // Check if we have seen a new target for soft max heap size or if a gc was requested. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 53e8d94658859..36822d9ed35bb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -75,11 +75,11 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); - ShenandoahObjectCountClosure _count(&local_cit); + ShenandoahObjectCountClosure count(&local_cit); using Closure = ShenandoahMarkRefsAndCountClosure; - Closure cl(q, rp, old_q, &_count); + Closure cl(q, rp, old_q, &count); mark_loop_work(&cl, ld, w, t, req); - _count.merge_table(global_cit); + count.merge_table(global_cit); } else #endif // INCLUDE_JFR { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index 61354cf1aef7f..9e9286d0b6dad 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -4,9 +4,9 @@ #if INCLUDE_JFR void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { - assert(_cit != nullptr, "The thread-local KlassInfoTables are not initialized"); + assert(_cit != nullptr, "The thread-local KlassInfoTable is not initialized"); assert(global_cit != nullptr, "Shenandoah KlassInfoTable is not initialized"); - MutexLocker x(TableMerge_lock, Mutex::_no_safepoint_check_flag); + MutexLocker x(ObjectCountMerge_lock, Mutex::_no_safepoint_check_flag); bool success = global_cit->merge(_cit); // Clear the _cit in the closure to ensure it won't be used again. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 876f67b7bd55f..25fb4b58eeef5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -129,10 +129,10 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { if (object_count_enabled) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); - ShenandoahObjectCountClosure _count(&local_cit); - ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &_count); + ShenandoahObjectCountClosure count(&local_cit); + ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &count); _root_scanner.roots_do(&init_mark, worker_id); - _count.merge_table(global_cit); + count.merge_table(global_cit); } else #endif // INCLUDE_JFR { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 20e4fb762bf7b..58e91217a3223 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -30,7 +30,6 @@ #include "oops/annotations.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" -#include "runtime/mutex.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; @@ -126,8 +125,8 @@ class KlassInfoTable: public StackObj { bool allocation_failed() { return _buckets == nullptr; } size_t size_of_instances_in_words() const; bool merge(KlassInfoTable* table); - bool merge_entry(const KlassInfoEntry* cie); + friend class KlassInfoHisto; friend class KlassHierarchy; }; diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 14406cc6245f4..b6bd415b279df 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -85,7 +85,7 @@ Monitor* InitCompleted_lock = nullptr; Monitor* BeforeExit_lock = nullptr; Monitor* Notify_lock = nullptr; Mutex* ExceptionCache_lock = nullptr; -Mutex* TableMerge_lock = nullptr; +Mutex* ObjectCountMerge_lock = nullptr; Mutex* TrainingData_lock = nullptr; Monitor* TrainingReplayQueue_lock = nullptr; #ifndef PRODUCT @@ -247,7 +247,7 @@ void mutex_init() { MUTEX_DEFN(SignatureHandlerLibrary_lock , PaddedMutex , safepoint); MUTEX_DEFN(SymbolArena_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(ExceptionCache_lock , PaddedMutex , safepoint); - MUTEX_DEFN(TableMerge_lock , PaddedMutex , nosafepoint); + MUTEX_DEFN(ObjectCountMerge_lock , PaddedMutex , nosafepoint); #ifndef PRODUCT MUTEX_DEFN(FullGCALot_lock , PaddedMutex , safepoint); // a lock to make FullGCALot MT safe #endif diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 87b483fa1bede..d08c757a34dc3 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -87,7 +87,7 @@ extern Monitor* InitCompleted_lock; // a lock used to signal thread extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates -extern Mutex* TableMerge_lock; // a lock used to synchronize merging a thread-local table into a global table +extern Mutex* ObjectCountMerge_lock; // a lock used to synchronize merging a thread-local object count histogram into a global one #ifndef PRODUCT extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT safe From 23283621f59afde506a432307c11155f14863d77 Mon Sep 17 00:00:00 2001 From: pf0n Date: Wed, 3 Sep 2025 04:22:45 +0000 Subject: [PATCH 103/104] Readded mutex --- src/hotspot/share/memory/heapInspection.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 58e91217a3223..e9314434450ca 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -30,6 +30,7 @@ #include "oops/annotations.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.hpp" +#include "runtime/mutex.hpp" #include "utilities/macros.hpp" class ParallelObjectIterator; From 8ce74f81957364d2b5dbd68fba7bf095192f68d7 Mon Sep 17 00:00:00 2001 From: pf0n Date: Thu, 4 Sep 2025 18:25:07 +0000 Subject: [PATCH 104/104] Testing to see if filtering objects work --- .../gc/shenandoah/shenandoahConcurrentMark.cpp | 3 ++- src/hotspot/share/gc/shenandoah/shenandoahMark.cpp | 3 ++- .../gc/shenandoah/shenandoahObjectCountClosure.cpp | 5 +++++ .../gc/shenandoah/shenandoahObjectCountClosure.hpp | 14 +++++++++++--- .../share/gc/shenandoah/shenandoahSTWMark.cpp | 3 ++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index c43a71f2b59bb..9abea1f1639a3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -179,7 +179,8 @@ void ShenandoahMarkConcurrentRootsTask::work(uint worker_id) { if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); - ShenandoahObjectCountClosure count(&local_cit); + ShenandoahIsAliveClosure is_alive; + ShenandoahObjectCountClosure count(&local_cit, &is_alive); ShenandoahMarkRefsAndCountClosure cl(q, _rp, old_q, &count); _root_scanner.roots_do(&cl, worker_id); count.merge_table(global_cit); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp index 36822d9ed35bb..458848cfea793 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMark.cpp @@ -75,7 +75,8 @@ void ShenandoahMark::mark_loop_prework(uint w, TaskTerminator *t, ShenandoahRefe if (object_count_enabled && !ShenandoahHeap::heap()->mode()->is_generational()) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); - ShenandoahObjectCountClosure count(&local_cit); + ShenandoahIsAliveClosure is_alive; + ShenandoahObjectCountClosure count(&local_cit, &is_alive); using Closure = ShenandoahMarkRefsAndCountClosure; Closure cl(q, rp, old_q, &count); mark_loop_work(&cl, ld, w, t, req); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp index 9e9286d0b6dad..10ea9f35990fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.cpp @@ -1,3 +1,4 @@ +#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahObjectCountClosure.hpp" #include "runtime/mutexLocker.hpp" @@ -14,4 +15,8 @@ void ShenandoahObjectCountClosure::merge_table(KlassInfoTable* global_cit) { assert(success, "Failed to merge thread-local table"); } +bool ShenandoahObjectCountClosure::should_visit(oop o) { + return _filter->do_object_b(o); +} + #endif // INCLUDE_JFR diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp index e5559ce915afa..be95f1654559a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjectCountClosure.hpp @@ -9,9 +9,13 @@ #if INCLUDE_JFR +class ShenandoahIsAliveClosure; + class ShenandoahObjectCountClosure { private: KlassInfoTable* _cit; + ShenandoahIsAliveClosure* _filter; + template inline void do_oop_work(T* p) { assert(p != nullptr, "Object is null"); @@ -19,17 +23,21 @@ class ShenandoahObjectCountClosure { assert(!CompressedOops::is_null(o), "CompressOops is null"); oop obj = CompressedOops::decode_not_null(o); assert(_cit != nullptr, "KlassInfoTable is null"); - _cit->record_instance(obj); + if (should_visit(obj)) { + _cit->record_instance(obj); + } } public: - ShenandoahObjectCountClosure(KlassInfoTable* cit) : _cit(cit) {} + ShenandoahObjectCountClosure(KlassInfoTable* cit, ShenandoahIsAliveClosure* is_alive) : _cit(cit), _filter(is_alive) {} // Record the object's instance in the KlassInfoTable inline void do_oop(narrowOop* o) { do_oop_work(o); } // Record the object's instance in the KlassInfoTable inline void do_oop(oop* o) { do_oop_work(o); } inline KlassInfoTable* get_table() { return _cit; } - + + bool should_visit(oop o); + // Merges the heap's KlassInfoTable with the thread's KlassInfoTable. // Clears the thread's table, so it won't be used again. void merge_table(KlassInfoTable* global_cit); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 25fb4b58eeef5..29c9d00934a7e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -129,7 +129,8 @@ void ShenandoahSTWMark::mark_roots(uint worker_id) { if (object_count_enabled) { KlassInfoTable* const global_cit = ShenandoahHeap::heap()->get_cit(); KlassInfoTable local_cit(false); - ShenandoahObjectCountClosure count(&local_cit); + ShenandoahIsAliveClosure is_alive; + ShenandoahObjectCountClosure count(&local_cit, &is_alive); ShenandoahMarkRefsAndCountClosure init_mark(queue, rp, nullptr, &count); _root_scanner.roots_do(&init_mark, worker_id); count.merge_table(global_cit);