diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java index de97ce2bc8ef..3529f737be8d 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java @@ -77,6 +77,7 @@ import com.oracle.svm.core.heap.RuntimeCodeCacheCleaner; import com.oracle.svm.core.heap.VMOperationInfos; import com.oracle.svm.core.jdk.RuntimeSupport; +import com.oracle.svm.core.jfr.JfrGCWhen; import com.oracle.svm.core.jfr.JfrTicks; import com.oracle.svm.core.log.Log; import com.oracle.svm.core.os.CommittedMemoryProvider; @@ -208,7 +209,9 @@ private void collectOperation(CollectionVMOperationData data) { GCCause cause = GCCause.fromId(data.getCauseId()); printGCBefore(cause.getName()); + JfrGCHeapSummaryEvent.emit(getCollectionEpoch(), JfrTicks.elapsedTicks(), getPolicy().getCurrentHeapCapacity().rawValue(), getChunkBytes().rawValue(), JfrGCWhen.BEFORE_GC); boolean outOfMemory = collectImpl(cause, data.getRequestingNanoTime(), data.getForceFullGC()); + JfrGCHeapSummaryEvent.emit(getCollectionEpoch(), JfrTicks.elapsedTicks(), getPolicy().getCurrentHeapCapacity().rawValue(), getChunkBytes().rawValue(), JfrGCWhen.AFTER_GC); printGCAfter(cause.getName()); finishCollection(); diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/JfrGCHeapSummaryEvent.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/JfrGCHeapSummaryEvent.java new file mode 100644 index 000000000000..4993ce18922e --- /dev/null +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/JfrGCHeapSummaryEvent.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 anycd + * questions. + */ +package com.oracle.svm.core.genscavenge; + +import org.graalvm.compiler.api.replacements.Fold; + +import org.graalvm.nativeimage.StackValue; +import org.graalvm.word.UnsignedWord; + +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.Uninterruptible; + +import com.oracle.svm.core.jfr.HasJfrSupport; +import com.oracle.svm.core.jfr.JfrEvent; +import com.oracle.svm.core.jfr.JfrGCWhen; +import com.oracle.svm.core.jfr.JfrNativeEventWriter; +import com.oracle.svm.core.jfr.JfrNativeEventWriterData; +import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess; + +class JfrGCHeapSummaryEvent { + + public static void emit(UnsignedWord gcEpoch, long start, long committedSize, long heapUsed, JfrGCWhen gcWhen) { + if (HasJfrSupport.get() && isEnabled()) { + emit0(gcEpoch, start, committedSize, heapUsed, gcWhen); + } + } + + @Uninterruptible(reason = "Accesses a JFR buffer.") + private static void emit0(UnsignedWord gcEpoch, long start, long committedSize, long heapUsed, JfrGCWhen gcWhen) { + + if (JfrEvent.GCHeapSummary.shouldEmit()) { + + JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); + JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); + + JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.GCHeapSummary); + + JfrNativeEventWriter.putLong(data, start); // @Label("Start Time") @Timestamp("TICKS") + // long startTime; + + JfrNativeEventWriter.putLong(data, gcEpoch.rawValue()); // @Label("GC Identifier") int + // gcId; + JfrNativeEventWriter.putLong(data, gcWhen.ordinal()); // @Label("When") String when; + + // VirtualSpace + JfrNativeEventWriter.putLong(data, 0L); // start + JfrNativeEventWriter.putLong(data, 0L); // committedEnd : ulong + JfrNativeEventWriter.putLong(data, committedSize); // committedSize : ulong + JfrNativeEventWriter.putLong(data, 0L); // reservedEnd : ulong + JfrNativeEventWriter.putLong(data, 0L); // reservedSize : ulong + + JfrNativeEventWriter.putLong(data, heapUsed); // @Unsigned @DataAmount("BYTES") + // @Label("Heap Used") @Description("Bytes + // allocated by objects in the heap") long + // heapUsed; + + JfrNativeEventWriter.endSmallEvent(data); + } + + } + + @Fold + static boolean isEnabled() { + return SubstrateOptions.UseSerialGC.getValue(); + } + +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java index 87f055bdd617..0f2201020ad8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvent.java @@ -60,6 +60,7 @@ public final class JfrEvent { public static final JfrEvent JavaMonitorWait = create("jdk.JavaMonitorWait"); public static final JfrEvent JavaMonitorInflate = create("jdk.JavaMonitorInflate"); public static final JfrEvent ObjectAllocationInNewTLAB = create("jdk.ObjectAllocationInNewTLAB"); + public static final JfrEvent GCHeapSummary = create("jdk.GCHeapSummary"); private final long id; private final String name; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java index 17bf45e6a47f..cfbc8f2ed20d 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrFeature.java @@ -173,6 +173,7 @@ public void afterRegistration(AfterRegistrationAccess access) { JfrSerializerSupport.get().register(new JfrGCCauseSerializer()); JfrSerializerSupport.get().register(new JfrGCNameSerializer()); JfrSerializerSupport.get().register(new JfrVMOperationNameSerializer()); + JfrSerializerSupport.get().register(new JfrGCWhenSerializer()); ThreadListenerSupport.get().register(SubstrateJVM.getThreadLocal()); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCWhen.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCWhen.java new file mode 100644 index 000000000000..9cdb4326148a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCWhen.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 com.oracle.svm.core.jfr; + +public enum JfrGCWhen { + BEFORE_GC("Before GC"), + AFTER_GC("After GC"); + + private final String gcWhen; + + JfrGCWhen(String gcWhen) { + this.gcWhen = gcWhen; + } + + public String getGcWhen() { + return this.gcWhen; + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCWhenSerializer.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCWhenSerializer.java new file mode 100755 index 000000000000..34b62dc44d4a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrGCWhenSerializer.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 com.oracle.svm.core.jfr; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +public class JfrGCWhenSerializer implements JfrSerializer { + @Platforms(Platform.HOSTED_ONLY.class) + public JfrGCWhenSerializer() { + } + + @Override + public void write(JfrChunkWriter writer) { + JfrGCWhen[] gcWhens = JfrGCWhen.values(); + + writer.writeCompressedLong(JfrType.GCWhen.getId()); + writer.writeCompressedLong(gcWhens.length); + for (JfrGCWhen when : gcWhens) { + writer.writeCompressedLong(when.ordinal()); + writer.writeString(when.getGcWhen()); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrType.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrType.java index e6bd8df17d8c..886cd1b9fcf2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrType.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrType.java @@ -44,6 +44,7 @@ public enum JfrType { FrameType("jdk.types.FrameType"), GCCause("jdk.types.GCCause"), GCName("jdk.types.GCName"), + GCWhen("jdk.types.GCWhen"), VMOperation("jdk.types.VMOperationType"), MonitorInflationCause("jdk.types.InflateCause"); diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestGCHeapSummaryEvent.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestGCHeapSummaryEvent.java new file mode 100644 index 000000000000..229ef4004616 --- /dev/null +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestGCHeapSummaryEvent.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 com.oracle.svm.test.jfr; + +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; + +import com.oracle.svm.core.jfr.JfrEvent; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; + +public class TestGCHeapSummaryEvent extends JfrRecordingTest { + + @Test + public void test() throws Throwable { + String[] events = new String[] {JfrEvent.GCHeapSummary.getName() }; + Recording recording = startRecording(events); + + System.gc(); + + stopRecording(recording, TestGCHeapSummaryEvent::validateEvents); + } + + private static void validateEvents(List events) { + assertTrue(events.size() > 0); + } +} diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/JfrFileParser.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/JfrFileParser.java index 01d486221ded..062b78ed08f1 100644 --- a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/JfrFileParser.java +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/JfrFileParser.java @@ -60,6 +60,8 @@ import com.oracle.svm.test.jfr.utils.poolparsers.ThreadGroupConstantPoolParser; import com.oracle.svm.test.jfr.utils.poolparsers.ThreadStateConstantPoolParser; import com.oracle.svm.test.jfr.utils.poolparsers.VMOperationConstantPoolParser; +import com.oracle.svm.test.jfr.utils.poolparsers.GCWhenConstantPoolParser; + public class JfrFileParser { private final Path path; @@ -88,6 +90,7 @@ public JfrFileParser(Path path) { addParser(JfrType.GCCause, new GCCauseConstantPoolParser(this)); addParser(JfrType.VMOperation, new VMOperationConstantPoolParser(this)); addParser(JfrType.MonitorInflationCause, new MonitorInflationCauseConstantPoolParser(this)); + addParser(JfrType.GCWhen, new GCWhenConstantPoolParser(this)); } private void addParser(JfrType type, ConstantPoolParser parser) { diff --git a/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/poolparsers/GCWhenConstantPoolParser.java b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/poolparsers/GCWhenConstantPoolParser.java new file mode 100644 index 000000000000..b1be4fd4444e --- /dev/null +++ b/substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/utils/poolparsers/GCWhenConstantPoolParser.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, 2023, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 com.oracle.svm.test.jfr.utils.poolparsers; + +import java.io.IOException; + +import org.junit.Assert; + +import com.oracle.svm.test.jfr.utils.JfrFileParser; +import com.oracle.svm.test.jfr.utils.RecordingInput; + +public class GCWhenConstantPoolParser extends AbstractSerializerParser { + public GCWhenConstantPoolParser(JfrFileParser parser) { + super(parser); + } + + @Override + public void parse(RecordingInput input) throws IOException { + int count = input.readInt(); + Assert.assertTrue(count > 0); + for (int i = 0; i < count; i++) { + addFoundId(input.readInt()); // Id. + Assert.assertFalse("GC when is empty!", input.readUTF().isEmpty()); + } + } +}