<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:"Yu Gothic";
panose-1:2 11 4 0 0 0 0 0 0 0;}
@font-face
{font-family:Aptos;
panose-1:2 11 0 4 2 2 2 2 2 4;}
@font-face
{font-family:"Iosevka Fixed SS16";
panose-1:2 0 5 9 3 0 0 0 0 4;}
@font-face
{font-family:"Times New Roman \(Body CS\)";
panose-1:2 11 6 4 2 2 2 2 2 4;}
@font-face
{font-family:Consolas;
panose-1:2 11 6 9 2 2 4 3 2 4;}
@font-face
{font-family:"\@Yu Gothic";
panose-1:2 11 4 0 0 0 0 0 0 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
font-size:10.0pt;
font-family:"Aptos",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Iosevka Fixed SS16";
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-size:10.0pt;
mso-ligatures:none;}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style>
</head>
<body lang="EN-US" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">One should probably use System.nanoTime() instead of .currentTimeMillis() ...<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16"">-andy<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-size:11.0pt;font-family:"Iosevka Fixed SS16""><o:p> </o:p></span></p>
<div id="mail-editor-reference-message-container">
<div>
<div style="border:none;border-top:solid #B5C4DF 1.0pt;padding:3.0pt 0in 0in 0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><b><span style="font-size:12.0pt;color:black">From:
</span></b><span style="font-size:12.0pt;color:black">openjfx-dev <openjfx-dev-retn@openjdk.org> on behalf of Thiago Milczarek Sayão <thiago.sayao@gmail.com><br>
<b>Date: </b>Thursday, August 8, 2024 at 03:47<br>
<b>To: </b>John Hendrikx <john.hendrikx@gmail.com><br>
<b>Cc: </b>openjfx-dev@openjdk.org <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: Detecting threading problems faster<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Nice! I will steal it if you don't mind.<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Em qua., 7 de ago. de 2024 às 15:55, John Hendrikx <<a href="mailto:john.hendrikx@gmail.com">john.hendrikx@gmail.com</a>> escreveu:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<p>For detecting long running tasks on the FX thread, there are some other options which you can do as a user (but perhaps we can support it directly within FX). I use this kind of code to detect long running things on the FX thread:<o:p></o:p></p>
<div>
<div>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">/**</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">* Adds a slow event warning whenever an event takes more than 10 ms to process. Note</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">* that time spent in nested event loops cannot be properly taken into account as time</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">* spent in nested event loops will be part of the event that triggered it giving false</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">* positives. In order for this time to be accurately reflected, the methods to enter</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">* a nested event loop in this class should be used instead of the ones in
</span><span style="font-size:11.0pt;font-family:Consolas;color:#3F3FBF">{@link Platform}</span><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">.</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">*</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">*
</span><b><span style="font-size:11.0pt;font-family:Consolas;color:#7F9FBF">@param</span></b><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF"> scene a Scene to which to add the slow event warning detection, cannot be null</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#3F5FBF">*/</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">public</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">
</span><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">static</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">
</span><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">void</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">
</span><span style="font-size:11.0pt;font-family:Consolas;color:#0066CC">addSlowEventWarning</span><span style="font-size:11.0pt;font-family:Consolas;color:black">(Scene scene) {<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">final</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> EventDispatcher eventDispatcher = scene.getEventDispatcher();<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">scene.setEventDispatcher(</span><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">new</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">
EventDispatcher() {<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">private</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> ScheduledFuture<StackTraceElement[]>
</span><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">future</span><span style="font-size:11.0pt;font-family:Consolas;color:black">;<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#646464">@Override</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">public</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> Event dispatchEvent(Event event, EventDispatchChain tail) {<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">if</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">(</span><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">future</span><span style="font-size:11.0pt;font-family:Consolas;color:black">
!= </span><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">null</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">) {<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">future</span><span style="font-size:11.0pt;font-family:Consolas;color:black">.cancel(</span><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">false</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">);<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">}<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">long</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> startTime = System.<i>currentTimeMillis</i>();<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">TIME_TRACKER</span><span style="font-size:11.0pt;font-family:Consolas;color:black">.enterNested(startTime);
</span><span style="font-size:11.0pt;font-family:Consolas;color:#3F7F5F">// nesting can happen in two ways, an event triggering another event, or when a nested event loop is entered</span><span style="font-size:11.0pt;font-family:Consolas;color:black"><o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">Event returnedEvent = eventDispatcher.dispatchEvent(event, tail);<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">long</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> endTime = System.<i>currentTimeMillis</i>();<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">long</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> timeSpentInNested =
</span><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">TIME_TRACKER</span><span style="font-size:11.0pt;font-family:Consolas;color:black">.exitNested(endTime);<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">if</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black">(timeSpentInNested > 10) {<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#0000A0">long</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> total = endTime - startTime;<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">LOGGER</span><span style="font-size:11.0pt;font-family:Consolas;color:black">.warning(</span><span style="font-size:11.0pt;font-family:Consolas;color:#2A00FF">"Slow
Event (self/total: "</span><span style="font-size:11.0pt;font-family:Consolas;color:black"> + timeSpentInNested +
</span><span style="font-size:11.0pt;font-family:Consolas;color:#2A00FF">"/"</span><span style="font-size:11.0pt;font-family:Consolas;color:black"> + total +
</span><span style="font-size:11.0pt;font-family:Consolas;color:#2A00FF">" ms @ level "</span><span style="font-size:11.0pt;font-family:Consolas;color:black"> +
</span><span style="font-size:11.0pt;font-family:Consolas;color:#0000C0">TIME_TRACKER</span><span style="font-size:11.0pt;font-family:Consolas;color:black">.getCurrentLevel() +
</span><span style="font-size:11.0pt;font-family:Consolas;color:#2A00FF">"): "</span><span style="font-size:11.0pt;font-family:Consolas;color:black"> + event);<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">}<o:p></o:p></span></p>
<p style="margin:0in;background:white"><b><span style="font-size:11.0pt;font-family:Consolas;color:#7F0055">return</span></b><span style="font-size:11.0pt;font-family:Consolas;color:black"> returnedEvent;<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">}<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">});<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">}<o:p></o:p></span></p>
<p style="margin:0in;background:white"><span style="font-size:11.0pt;font-family:Consolas;color:black">--John
<o:p></o:p></span></p>
</div>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On 05/08/2024 17:17, Thiago Milczarek Sayão wrote:<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Hi, <o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Interesting idea. We have this problem specially when Junior developers touch the code.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">The other way around would be nice too - if some I/O task executes on the FX thread.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">This can make the OS think the application hanged and offer to kill it, since it won't respond to "pings". And I/O tasks processing time may vary between installations. Also causes "white screens" since it
blocks painting.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">-- Thiago.<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Em seg., 5 de ago. de 2024 às 11:59, Kevin Rushforth <<a href="mailto:kevin.rushforth@oracle.com" target="_blank">kevin.rushforth@oracle.com</a>> escreveu:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<p class="MsoNormal"><span style="font-size:12.0pt">Wouldn't it be better to implement this check in assert to avoid any impact in production?<o:p></o:p></span></p>
</blockquote>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt"><br>
No. Using an assert in a case like this is an anti-pattern. A call to assert in a library such as JavaFX is only appropriate for checking an invariant in internal logic. If we are going to go down this route of doing a thread check when mutating properties
of "live" nodes, we will throw the same IllegalStateException that is currently thrown by some methods on Stage and Scene.<br>
<br>
As for the proposal itself, adding this check is an interesting idea. We considered doing this back in the JDK 7 (JavaFX 2) time frame, but decided not to pursue it then. I think the idea is worth further discussion. I would limit any thread checking to setting
the property. It would be too restrictive (and largely unnecessary) to prevent reading a property from the application thread.<br>
<br>
The things to consider would be:<br>
<br>
1. What is the performance hit of doing this check on the setting of every property?<br>
2. What is the effect on bound properties?<br>
3. How intrusive is it in the code?<br>
4. Should we add a property to enable / disable the thread check, possibly a three- or four-valued property (allow|warn|debug?|deny), as was recently done in JEP 471 for sun.misc.Unsafe memory access methods. If so, what should the default be?<br>
<br>
My quick take is that if this can be done in a minimally intrusive manner with low overhead, we should consider pursing this. As for 4, my preference would be to add a three- or four-valued system property to control the check, with "warn" as the default initially,
changing the default to "disallow" in a subsequent version. This would, of course, require a lot of testing.<br>
<br>
-- Kevin<br>
<br>
<o:p></o:p></span></p>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">On 8/4/2024 8:40 PM, quizynox wrote:<o:p></o:p></span></p>
</div>
<blockquote style="margin-top:5.0pt;margin-bottom:5.0pt">
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">Hello,<br>
<br>
Wouldn't it be better to implement this check in assert to avoid any impact in production?<o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span style="font-size:12.0pt">пн, 5 авг. 2024</span><span style="font-size:12.0pt;font-family:"Arial",sans-serif"> </span><span style="font-size:12.0pt">г. в 03:30, John Hendrikx <<a href="mailto:john.hendrikx@gmail.com" target="_blank">john.hendrikx@gmail.com</a>>:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<p class="MsoNormal" style="margin-bottom:12.0pt"><span style="font-size:12.0pt">Hi list,<br>
<br>
I know of quite some bugs and users that have been bitten by the <br>
threading model used by JavaFX. Basically, anything directly or <br>
indirectly linked to an active Scene must be accessed on the FX thread. <br>
However, as FX also allows manipulating nodes and properties before <br>
they're displayed, there can be no "hard" check everywhere to ensure we <br>
are on the FX thread (specifically, in properties).<br>
<br>
Now, I think this situation is annoying, as a simple mistake where a <br>
Platform.runLater wrapper was forgotten usually results in programs <br>
operating mostly flawlessly, but then fail in mysterious and random and <br>
hard to reproduce ways. The blame is often put on FX as the resulting <br>
exceptions will almost never show the user code which was the actual <br>
culprit. It can result in FX being perceived as unstable or buggy.<br>
<br>
So I've been thinking if there isn't something we can do to detect these <br>
bugs originating from user code much earlier, similar to the <br>
`ConcurrentModificationException` the collection classes do when <br>
accessed in nested or concurrent contexts.<br>
<br>
I think it may be possible to have properties check whether they're part <br>
of an active scene without too much of an performance impact, possibly <br>
even behind a switch. It would work like this:<br>
<br>
Properties involved with Nodes will have an associated bean instance <br>
(`getBean`). This is an object, but we could check here if this <br>
instance implements an interface:<br>
<br>
if (getBean() instanceof MayBePartOfSceneGraph x) {<br>
if (x.isPartOfActiveScene() && !isOnFxThread()) {<br>
throw new IllegalStateException("Property must only be <br>
used from the FX Application Thread");<br>
}<br>
}<br>
<br>
This check could be done on every set of the property, and potentially <br>
on every get as well. It should be relatively cheap, but will expose <br>
problematic code patterns at a much earlier stage. There's a chance <br>
that this will "break" some programs that seemed to be behaving <br>
correctly as well, so we may want to put it behind a switch until such <br>
programs (or libraries) can be fixed.<br>
<br>
What do you all think?<br>
<br>
--John<br>
<br>
(*) Names of methods/interfaces are only used for illustration purposes, <br>
we can think of good names if this moves forward.<o:p></o:p></span></p>
</blockquote>
</div>
</blockquote>
<p class="MsoNormal"><span style="font-size:12.0pt"><o:p> </o:p></span></p>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</body>
</html>