Custom scheduler: Using loom for deterministic simulation testing

Robert Engels robaho at me.com
Tue Jul 8 14:31:20 UTC 2025


It certainly seems like a custom OpenJDK build would be an easier path for something like this. 

I am curious though - what if the application code uses async native type calls (NIO). What would be synchronous testing in this? I assume it would have to behave as if it was synchronous - callback immediately called - but that’s not how it works in the real world - so what are you testing ?

> On Jul 8, 2025, at 9:23 AM, Yannick Lecaillez <yannick.lecaillez at pingidentity.com> wrote:
> 
> 
> Hi,
> 
> We're also working a Deterministic Simulation Testing on top of loom for some times now and though
> you might be interested by this feedback:
> 
> One goal of our DST is to be able to run applications without having to change application
> code. To do so, we did a lot of trickery in JDK API using Agent (rewired System.currentTimeMillis(),
> System.nanoTime(), jdk.internal.misc.VMn ...). We're also doing call-site instrumentation in application
> code to replace every new Thread() by Thread.ofVirtual().start() (all virtual threads are backed by a
> single-platform thread, effectively a run loop). One limitation is that this does not work for
> `class Foo extends Thread'. Effectively application code must be changed to replace 'extends Thread'
> constructions by using composition. I don't think there is any solution to this.
> 
> Another challenging aspect which might benefit from a JDK modification is dealing with object monitor.
> Since JDK 24, object monitor in virtual-threads don't pin the carrier-thread anymore. The mechanism relies
> on a queue which is polled by a thread-unblocker platform thread. To keep determinism, we rewrote the
> "unblockVirtualThreads()" loop (through Agent) and we select and push unblocked pending virtual-thread
> backed by the DST into another queue which is polled by the run-loop after every iteration (while the
> threads not backed by the DST are unblocked immediately). That appears to work but is really inefficient
> in addition to being complex: it requires checking for every virtual thread backed by the DST whether
> it is present in "onWaitingList". At that time, we made the choice to not modify the JDK but that
> maybe something we could revisit given the recent interest on this topic appearing on this list.
> 
> ImmutableCollections (SALT32L and REVERSE) is another source of non-determinism that we "fixed" with
> our Agent. It would be helpful if the JDK provided a property to set the seed (but I can see also how
> doing so would kind of defeat the purpose of SALT32L).
> 
> ThreadLocalRandom.current() was also challenging as it is not possible to provide a seed. We ended to
> rewire #nextSeed() to the DST's Random#nextLong()
> 
> Regarding Object#hashCode()/System.identityHashCode() we don't have a solution. So far we think they
> could only impact iteration order of Hash(Map|Set) to which we're evaluating replacing these by
> LinkedHashMap/LinkedHashSet.
> 
> It feels like some localized modifications in the JDK would bring enough flexibility to simplify our Agent
> drastically. Otherwise, we'll probably have to adapt it for every JDK version.  I'll try to take the time to propose
> a PR about these to make the discussion more concrete.
> 
> Best Regards,
> Yannick. 
> 
> CONFIDENTIALITY NOTICE: This email may contain confidential and privileged material for the sole use of the intended recipient(s). Any review, use, distribution or disclosure by others is strictly prohibited.  If you have received this communication in error, please notify the sender immediately by e-mail and delete the message and any file attachments from your computer. Thank you.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20250708/a7815ce1/attachment-0001.htm>


More information about the loom-dev mailing list