-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add support for JFR monitor enter events #4651
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 support for JFR monitor enter events #4651
Conversation
We use the Oracle Contributor Agreement to make the copyright of contributions clear. We don't have a record of you having signed this yet, based on your email address rtoyonag -(at)- rtoyonag -(dot)- remote -(dot)- csb. You can sign it at that link. If you think you've already signed it, please comment below and we'll check.
We use the Oracle Contributor Agreement to make the copyright of contributions clear. We don't have a record of you having signed this yet, based on your email address 35396843+roberttoyonaga -(at)- users -(dot)- noreply -(dot)- github -(dot)- com. You can sign it at that link. If you think you've already signed it, please comment below and we'll check. |
Have you tried |
@christianhaeubl Could you please review this PR or suggest someone who could do so? Thanks! |
@@ -0,0 +1,48 @@ | |||
package src.com.oracle.svm.core.src.com.oracle.svm.core.jfr.events; |
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 add a copyright header.
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.
done!
public class JavaMonitorEnterEvent { | ||
|
||
@Uninterruptible(reason = "Accesses a JFR buffer.") | ||
public static void emit(Object obj, org.graalvm.nativeimage.IsolateThread previousOwner,long startTicks) { |
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 run mx checkstyle
and use the eclipse formatter.
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.
done!
@@ -255,8 +257,27 @@ private static void slowPathMonitorEnter(Object obj) { | |||
@RestrictHeapAccess(reason = NO_LONGER_UNINTERRUPTIBLE, access = Access.UNRESTRICTED) | |||
@Override | |||
public void monitorEnter(Object obj) { | |||
long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); |
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.
HotSpot only emits the event if there is a contention, i.e., no JFR event is emitted for the fast path. We need something similar.
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've now implemented this behavior by only emitting events if tryLock() fails to get the lock
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 new approach doesn't work:
- You only fill
monitorOwners
when a lock contention is happening. So, you will usually keep track of an outdated value and not of the latest previous owner. One possible solution would be to introduce a customReentrantLock
subclass that keeps track of the previous owner in a field. Writing the JFR thread id to that field should be cheap enough so that you can do it in the fast path. - There is no guarantee that your call to
lockObject.lock();
really runs into a contention. So, you will emit unnecessary JFR events from time to time. To solve that, you will probably need to add a method that is similar tolock()
that returns if it was necessary to park the thread because of a contention.
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.
yes I see! Thank you Christian. I have used the solution you suggested for 1.
For 2, wouldn't tryLock()
returning false indicate that there is contention? Is the problem that the lock may be released in between the call to tryLock()
and lock()
? I think the Hotspot code makes one attempt to acquire the lock (+1 optional spin) and upon failure treats it as contention.
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.
ad 2. you are right, I thought that HotSpot is more strict. So, the current solution is good enough.
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class); | ||
JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data); | ||
|
||
if (emit0(data, obj, previousOwner, startTicks, SubstrateJVM.get().isLarge(JfrEvent.JavaMonitorEnter)) == com.oracle.svm.core.jfr.JfrEventWriteStatus.RetryLarge) { |
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.
There shouldn't be any need for the retry mechanism as this event has a fixed size (it only contains primitive data). Search the code base for JfrNativeEventWriter.beginSmallEvent(...)
to find examples where we emit JFR events that have a fixed size.
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 also use your Red Hat email address for all commits. Otherwise, we can't merge the changes to master easily.
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.
ok I should be using my redhat email now. I got rid of the retry.
3316193
to
3ee246d
Compare
Hello Robert Toyonaga, thanks for contributing a PR to our project! We use the Oracle Contributor Agreement to make the copyright of contributions clear. We don't have a record of you having signed this yet, based on your email address rtoyonag -(at)- redhat -(dot)- com. You can sign it at that link. If you think you've already signed it, please comment below and we'll check. |
Robert Toyonaga has signed the Oracle Contributor Agreement (based on email address rtoyonag -(at)- redhat -(dot)- com) so can contribute to this repository. |
@@ -255,8 +257,27 @@ private static void slowPathMonitorEnter(Object obj) { | |||
@RestrictHeapAccess(reason = NO_LONGER_UNINTERRUPTIBLE, access = Access.UNRESTRICTED) | |||
@Override | |||
public void monitorEnter(Object obj) { | |||
long startTicks = com.oracle.svm.core.jfr.JfrTicks.elapsedTicks(); |
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.
ad 2. you are right, I thought that HotSpot is more strict. So, the current solution is good enough.
import org.graalvm.nativeimage.CurrentIsolate; | ||
import com.oracle.svm.core.jfr.SubstrateJVM; | ||
|
||
public class OwnedReentrantLock extends ReentrantLock { |
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.
JavaMonitor
might be a better name.
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.
renamed!
currOwnerTid = SubstrateJVM.get().getThreadId(CurrentIsolate.getCurrentThread()); | ||
} | ||
|
||
public boolean tryLockOwnedLock() { |
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.
You could rename this method to enter
or monitorenter
.
If you move the call to JavaMonitorEnterEvent.emit(...);
into this method as well, then it should be sufficient to store the latest owner in a single field.
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.
renamed and moved call to emit event
@@ -192,8 +193,10 @@ public class MultiThreadedMonitorSupport extends MonitorSupport { | |||
* Secondary storage for monitor slots. Synchronized to prevent concurrent access and | |||
* modification. | |||
*/ | |||
private final Map<Object, ReentrantLock> additionalMonitors = new WeakIdentityHashMap<>(); | |||
private final Map<Object, OwnedReentrantLock> additionalMonitors = new WeakIdentityHashMap<>(); | |||
private final Map<Object, Long> monitorOwners = new WeakIdentityHashMap<>(); |
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.
The fields monitorOwners
and monitorOwnersLock
are unused.
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.
removed!
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, I will try to merge this change in the next couple days.
Added support for JFR jdk.JavaMonitorEnter events. These events provide information on when threads get blocked trying to acquire a lock.