EA builds with changes to object monitor implementation to avoid pinning with virtual threads

Patricio Chilano Mateo patricio.chilano.mateo at oracle.com
Wed Feb 28 05:31:14 UTC 2024


Hi Masoud,


Thanks for testing the latest EA build.

On 2/27/24 3:28 PM, masoud parvari wrote:
> public class VirtualThreadPerformanceTest {
>
>     public static void main(String[] args) throws InterruptedException {
>         int size = 1000;
>         test(false, size);
>         test(true, size);
>     }
>
>     private static void test(boolean isVirtual, int size) throws 
> InterruptedException {
>         ExecutorService executorService = isVirtual == true ? 
> Executors.newVirtualThreadPerTaskExecutor()
>             : 
> Executors.newThreadPerTaskExecutor(Thread.ofPlatform().factory());
>         CountDownLatch latch = new CountDownLatch(size);
>         long start = System.currentTimeMillis();
>         Object object = new Object();
>         for (int i = 0; i < size; i++) {
>             executorService.submit(() -> {
>                 synchronized (object) {
>                     try {
>                         object.wait(100);
>                     } catch (InterruptedException e) {
>                         //do nothing;
>                     }
>                 }
>                 latch.countDown();
>             });
>         }
>         synchronized (object) {
>             object.notifyAll();
>         }
>         latch.await();
>         long duration = System.currentTimeMillis() - start;
>         System.out.println((isVirtual? "Virtual" : "Platform") + " 
> took " + duration + " milliseconds");
>     }
> }
>
> To my surprise, Virtual thread is significantly slower than platform 
> thread here. 4x-5x. And also virtual thread on new build is 
> consistently slower than java 21 in this scenario, around 100-200 
> milliseconds in above example which is significant. Is this already 
> known and expected? Would you please provide some insights on what is 
> happening here?
The reason why you see this difference is because with platform threads 
all 1000 threads will be started and will wait simultaneously, as 
releasing the monitor on wait() allows another thread to enter it and 
wait() too. For virtual threads, since we still pin on Object.wait(), we 
can only run as many threads as workers in the FJP. So the code will 
behave like running in batches, where after the first batch finishes 
waiting, the next one will run. We actually compensate on Object.wait() 
until a max pool size of 256, which will give you around 4 batches, so 
that explains the 4x-5x you are seeing. If you increase the wait time 
you will see this more clearly. This behavior will be fixed once we 
remove pinning on Object.wait(). As for the difference between virtual 
threads themselves against jdk21 I see a difference too. I'll need to 
investigate a bit more to check exactly where the overhead is coming from.

> And also on the classloader side, I was wondering if there are some 
> plans to change classloader implementation (i.e to use a Reentrantlock 
> per class rather than synchronizing on an object per class)
> or do you expect the limitation of having native frames on the stack 
> causing thread pinning goes away rather soon and hence no need to 
> change classloader impl?
Note though that in this class loading/initialization deadlocks the 
underlying issue is that we pin because there are native frames in the 
stack, so replacing the synchronized with a j.u.c lock will still lead 
to the same issue.

Thanks,
Patricio
> Kind regards,
> Masoud
>
>
> On Thu, Feb 22, 2024 at 1:09 PM Alan Bateman <Alan.Bateman at oracle.com> 
> wrote:
>
>     On 21/02/2024 10:49, masoud parvari wrote:
>     > :
>     >
>     > And of course I am aware of Spring Boot 3.2+ releases. The point
>     of my
>     > load testing was testing an application with lots of contention on
>     > objectmonitors rather than a setup where most of the synchronized
>     > blocks have been replaced by ReentrantLock.
>     >
>     > So I would argue that for the mere purpose of testing Loom's new
>     > object monitor implementation, and making sure hanging is not
>     > happening, Spring boot 2.7.x is a better candidate than 3.2.x. I
>     hope
>     > this helps to clarify the testing's goal.
>     >
>
>     I'm not familiar with the different versions of Spring but it sounds
>     like the 2.7.x has more uses of object monitors. That is useful to
>     know.
>
>     Note that the EA builds have been refreshed to pick up recent changes
>     (and changes from main line). There is a change to the object monitor
>     implementation that makes blocked threads that are pinned compete
>     with
>     the chosen successor when some thread exits a monitor. That should
>     help
>     with some of the cases where resolving class references is calling
>     through the VM to load classes. Also one of your mails mentioned that
>     your JFR recordings didn't have all the expected
>     jdk.VirtualThreadPinned
>     events. There are three cases where jdk.VirtualThreadPinned is
>     recorded,
>     one of these missed the first EA build.
>
>     -Alan
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20240228/7177bdda/attachment.htm>


More information about the loom-dev mailing list