-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add JFR GCHeapSummary event implementation #6466
Conversation
Could you take a look at this please, @roberttoyonaga? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @kazukg! Thanks for contributing. I've added a few minor comments.
|
||
public static void emitJfrGCHeapSummaryEventBeforeGC(UnsignedWord gcEpoch,long start,long heapUsed) { | ||
if (hasJfrSupport() ) { | ||
jfrSupport().emitGCHeapSummaryEventBeforeGC(gcEpoch, start,heapUsed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you run the eclipse formatter please? As well as mx checkstyle
. I think that could help fix some of the PR gate issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @roberttoyonaga !
Thank you for confirming. I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made changes to the source code and ran mx checkstyle
on the substratevm folder, verifying that there are no errors.
} | ||
|
||
@Uninterruptible(reason = "Accesses a JFR buffer.") | ||
public void emitGCHeapSummaryEventAfterGC(UnsignedWord gcEpoch, long start, long heapUsed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If emitGCHeapSummaryEventAfterGC(UnsignedWord, long, long)
and emitGCHeapSummaryEventBeforeGC(UnsignedWord, long, long)
are basically the same, why not just add another method emitGCHeapSummaryEvent(UnsignedWord, long , long, JfrGCWhen)
to reduce duplication?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roberttoyonaga
Could you review the changes I made to the source code?
public void beforeAnalysis(BeforeAnalysisAccess access) { | ||
if (HasJfrSupport.get()) { | ||
|
||
//ImageSingletons.add(JfrGCWhens.class, new JfrGCWhens()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can remove this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed it.
|
||
|
||
@AutomaticallyRegisteredFeature | ||
class JfrGCHeapSummaryEventFeature implements InternalFeature { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think this should actually be similar to JfrGCEventFeature
and only be included if the default SerialGC is being used. See isInConfiguration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refered to the source code of JfrGCEventFeature, and added isInConfiguration.
int id = whens.length; | ||
JfrGCWhen result = new JfrGCWhen(id, when); | ||
|
||
JfrGCWhen[] newArr = Arrays.copyOf(whens, id + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of having the logic this method provides, is there any reason you can't just hardcode initialize the array with "Before GC" and "After GC" JfrGCWhens? Is there a possibility of needing to add other JfrGCWhens in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe that we will need to add another JfrGCWhen in the future.
I would modify the code to hardcode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the source code to hardcode the initialization of JfrGCWhens.whens, and added getBeforeGCWhen and getAfterGCWhen methods to allow JfrGCHeapSummaryEventSupport to obtain their values.
Removing unnecessary imports.
- Added `emitGCHeapSummaryEvent` method to reduce duplication. - Hardcoded initialization of `JfrGCWhens.whens`.
Added isInConfiguration to include JfrGCHeapSummaryEventFeature only when the default SerialGC is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making those changes. I added a couple more minor comments.
@@ -44,6 +44,8 @@ public enum JfrType { | |||
FrameType("jdk.types.FrameType"), | |||
GCCause("jdk.types.GCCause"), | |||
GCName("jdk.types.GCName"), | |||
GCWhen("jdk.types.GCWhen"), | |||
VirtualSpace("jdk.types.VirtualSpace"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, it does seem unnecessary. Initially, I added it without fully understanding it. I will remove it and verify that it does not affect the functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed Definition of Virtual Space from JrfType.
|
||
class JfrGCHeapSummaryEventSupport { | ||
|
||
private final JfrGCWhen before; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be simpler if you didn't cache these JfrGCWhen
s and instead just called JfrGCWhens.singleton().getBeforeGCWhen()
and JfrGCWhens.singleton().getAfterGCWhen()
from emitGCHeapSummaryEventBeforeGC
and emitGCHeapSummaryEventAfterGC
respectively?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have completed it.
// VirtualSpace | ||
JfrNativeEventWriter.putLong(data, 0L); // start | ||
JfrNativeEventWriter.putLong(data, 0L); // committedEnd : ulong | ||
JfrNativeEventWriter.putLong(data, 0L); // committedSize : ulong |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some thoughts: You could try using GCImpl.getPolicy().getCurrentHeapCapacity()
to record the committedSize
. I'm not certain, but reservedSize
might not be applicable here, so maybe it makes the most sense to leave reservedEnd
and reservedSize
as 0 for now anyway. You listed these as non-goals so perhaps they can be done at a later time instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the advice. I am not currently able to try it out but I will do so in a few days based on your recommendation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added code to output the committed size, and I have verified that the committed size is recorded in jdk.GCHeapSummary.
jdk.GCHeapSummary {
startTime = 07:17:28.397
gcId = 0
when = "Before GC"
heapSpace = {
start = 0x00000000
committedEnd = 0x00000000
committedSize = 120.0 MB
reservedEnd = 0x00000000
reservedSize = 0 bytes
}
heapUsed = 48.1 MB
}
jdk.GCHeapSummary {
startTime = 07:17:28.398
gcId = 0
when = "After GC"
heapSpace = {
start = 0x00000000
committedEnd = 0x00000000
committedSize = 105.0 MB
reservedEnd = 0x00000000
reservedSize = 0 bytes
}
heapUsed = 599.8 kB
}
- Changed not to cache - Improved code to emit committed Size.
Thank you for making those changes. This seems good to me now. @christianhaeubl when you have time, can you have a look at this as well to see if it's ready for integration? |
|
||
class JfrGCHeapSummaryEventSupport { | ||
|
||
public void emitGCHeapSummaryEventBeforeGC(UnsignedWord gcEpoch, long start, long committedSize, long heapUsed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: As a refactoring, you could get rid of emitGCHeapSummaryEventBeforeGC
and emitGCHeapSummaryEventAfterGC
and call emitGCHeapSummaryEvent(UnsignedWord , long , long , long , JfrGCWhen)
directly from emitJfrGCHeapSummaryEventBeforeGC
and emitJfrGCHeapSummaryEventAfterGC
(by supplying JfrGCWhens.singleton().getBeforeGCWhen()
or JfrGCWhens.singleton().getAfterGCWhen()
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do that.
|
||
public class JfrGCWhens { | ||
|
||
private JfrGCWhen[] whens = new JfrGCWhen[]{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think this can be final
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR, I added a few comments.
@@ -0,0 +1,54 @@ | |||
/* | |||
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please adjust the copyright headers of the files that you added so that they contain the correct year (it seems that you copy/pasted them from other files).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for pointing that out.
I was copying and pasting the headers from other files.
I have made some modifications to several files, in addition to the ones I added. Do I need to update the copyright headers of those files as well?
Specifically, the files in question are JfrEvent, JfrFeature, JftType, and JftFileParser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the existing files that you modified: you can update the copyright headers if you want to but you don't need to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for reply.
I only modify the copyright headers of the files that I've added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have completed it.
|
||
import com.oracle.svm.core.Uninterruptible; | ||
|
||
public class JfrGCWhen { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use an enum
instead of a class
. Then, you also don't need the class JfrGCWhens
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have completed it.
import com.oracle.svm.core.jfr.JfrNativeEventWriterData; | ||
import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess; | ||
|
||
class JfrGCHeapSummaryEventSupport { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class is stateless, so all its methods can be static
. After doing that change, you can merge this class with JfrGCHeapSummaryEvent
and you can remove the class JfrGCHeapSummaryEventFeature
. In the end, your code should look similar to the class ThreadParkEvent
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for providing a specific example.
I will refer to the implementation of ThreadParkEvent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have modified JfrGCHeapSummaryEvent to be composed solely of static methods.
Thanks, I did further cleanups on top, see #6705. I also changed how the used/committed heap size is queried so that the logic is more consistent with other places where we are already querying that information. Let me know if you see any issues with those changes. This PR should get merged in the next few days. |
TL;DR
This pull request allows native applications to emit jdk.GCHeapSummary which is a jfr-event.
Jdk.GCHeapSummary is a jfr-event that has not yet been implemented.
GCHeapSummary is useful for observing changes of usedHeapSize that occur before and after a garbage collection event.
The sample events
We can visually monitor the heap usage of the application using VisualVM or JDK Mission Control.
Goals
Implement Start Time, gcId(gcEpoch), gcWhen, usedHeapSize in GCHeapSummary.
Non-Goals
Do not yet implement start, committedEnd, committedSize, reservedEnd, reservedSize in GCHeapSummary.
Because I've been struggling to find out where I can obtain those specific values.
If someone can offer suggestions on how to accomplish those tasks, I am willing to give it a shot.
Details
I developed it with reference to the implementation of jdk.GarbageCollection.
jdk.GCHeapSummary
.Added JfrGCWhen to manage strings like "Before GC" and "After GC".
Test Code
I have verified that I can display graphs using VisualVM or JDK Mission Control.