-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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 some JFR event tests #4932
Add some JFR event tests #4932
Conversation
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 working on test cases for certain JFR events.
In a lot of your test cases, you try to use Thread.sleep()
to ensure that multiple threads do something in a particular order. An approach like does not work reliably (especially if the machine has high load) and is therefore neither feasible for production code nor for test cases. You will need to switch to some kind of proper synchronization (e.g., ReentrantLock
or a spin lock in case that you want to avoid that certain JFR events are emitted).
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/JfrTest.java
Outdated
Show resolved
Hide resolved
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/JfrTest.java
Outdated
Show resolved
Hide resolved
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaMonitorEnter.java
Outdated
Show resolved
Hide resolved
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaMonitorEnter.java
Outdated
Show resolved
Hide resolved
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaMonitorEnter.java
Outdated
Show resolved
Hide resolved
simpleNotifyName = tn.getName(); | ||
|
||
tw.start(); | ||
Thread.sleep(50); |
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 also won't work reliably.
if (!struct.<RecordedClass> getValue("monitorClass").getName().equals(Helper.class.getName())) { | ||
continue; | ||
} | ||
assertTrue("Event is wrong duration.", isGreaterDuration(Duration.ofMillis(MILLIS), event.getDuration())); |
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 won't work reliably at the moment, see comments below.
|
||
public synchronized void consume() throws InterruptedException { | ||
// give the producers a headstart so they can start waiting | ||
wait(MILLIS); |
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 won't work reliably.
notifierName = unheardNotifierThread.getName(); | ||
|
||
timeoutThread.start(); | ||
Thread.sleep(10); |
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 doesn't work reliably.
if (!eventThread.equals(sleepingThreadName)) { | ||
continue; | ||
} | ||
if (!isEqualDuration(event.getDuration(), Duration.ofMillis(MILLIS))) { |
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 won't work reliably.
Thank you for the review Christian! I have updated the thread synchronization to be more reliable and removed the cases where sleeping is used to try to enforce ordering. Please let me know if there are still 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.
Thanks for the changes this already improves the situation. However, there is still one problematic pattern: querying Thread.getState()
in a loop is unreliable because it doesn't tell the reason why a thread is blocked or waiting. So, the following can happen:
- Thread A calls
Thread.getState()
on thread B and checks if thread B is blocked or waiting. - Thread B blocks or waits in JDK-internal code while the thread is being started (i.e. before it even reaches
run()
). - Thread A sees the changed thread status and assumes that thread B is blocked at the right position in
run()
.
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaMonitorEnter.java
Outdated
Show resolved
Hide resolved
Thread.sleep(10); | ||
} | ||
blockedAtCritical = true; | ||
helper.doWork(); |
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 setting/checking of blockedAtCritical
enough to guarantee the thread is blocking where we expect it to? I don't think it's possible to use the same pattern I've updated the monitor wait tests to. This is because monitor enter events don't seem to be emitted upon re-entry to synchronized blocks.
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, this should work. The name blockedAtCritical
is a bit misleading though because the thread is not blocked yet (thread B just reached a point where thread A can use thread.getState()
reliably to determine if thread B is blocked).
Thread.sleep(10); | ||
} | ||
blockedAtCritical = true; | ||
helper.doWork(); |
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, this should work. The name blockedAtCritical
is a bit misleading though because the thread is not blocked yet (thread B just reached a point where thread A can use thread.getState()
reliably to determine if thread B is blocked).
substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestJavaMonitorEnter.java
Outdated
Show resolved
Hide resolved
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, your PR will be merged to master in the next couple days.
Add some tests for recently added JFR events:
Each test generates the desired events to test, creates a JFR snapshot, and inspects the snapshot. There are 4 jdk.JavaMonitorWait tests that each cover a different case (time out, interruption, notify all, notify).