Repository navigation
fix (display): leaked runtime when display loads follow each other quickly - #4017
emilioheredia-source wants to merge 2 commits into
Conversation
…ckly loadDisplayFile() disposed only the display that was already shown. A load still running in the background was not tracked, so a second load, for example from a double click on 'back', left it running: its runtime and PVs stayed active until Phoebus exits, and whichever load finished last was shown, not the latest one. Closing the display while a load was running gave a 'Cannot load model' error after the display was gone. Loads now run one at a time up to the start of their runtime. Each load disposes the previous display once that display has been started. A load that was replaced by a newer one, or by closing the display, is skipped, and an error of a replaced load is only logged.
|
@emilioheredia-source , this looks very interesting. Would you mind testing a case where a large number (>10) of non-trivial displays are open, maybe across multiple windows? The test should just shut down Phoebus and restart to recreate the displays as they were when shutting down (default Phoebus behavior). Reason I ask is to figure out how user experience would be affected, e.g. seemingly longer time to restore the view when launching Phoebus. |
Restoring many displays at startup was about 0.4 s slower than on master: each load went to the UI thread twice, once to dispose the shown display before loading, then to represent the new one, and the first layout pass of the restored windows ran in between. Now the shown display remains until the new one is loaded, then a single UI step disposes it and represents the new one. A 'Loading' message is only shown when nothing is shown yet, as before.
|
Thanks, that was a good question. The test found a real slowdown, which is fixed now. Setup: 15 displays from the examples folder (10_scripts, 01_main, 11_datasources, 12_formulas, plots_xy, plots_image, structure_tabs, monitors_table, monitors_symbols, ...), 5 tabs in each of 3 windows, saved as the memento. Phoebus is started and restores them. I measured the time from launching Phoebus until the last display logged "Done with representing model", alternating master and the PR, on Xvfb with software rendering.
The first version was about 0.4 s slower. Each load went to the UI thread twice: once to dispose the shown display before loading, then again to represent the new one. At startup, the first layout pass of the restored windows ran in between, so every display waited for it. The new commit disposes the shown display and represents the new one in a single UI step, after the new display has been loaded, as master does for the representation. With that, restoring takes the same time as on master. One visible difference when navigating: the shown display now remains until the new one is ready, instead of being replaced by a "Loading ..." message right away. The first display of a tab still shows the message. In case it helps to judge the impact: we came across the leak while adding the mouse back/forward buttons for our operators, who navigate regularly with Back and Forward in EDM-style windows. A double click on the toolbar's Back button is enough to leave the skipped display's PVs connected until Phoebus exits. |
|
|
Thanks @emilioheredia-source I believe we have moved the file loading off the UI thread due to various performance issues discovered in BOY. This is particularly true if you have a bad script... That having being said the resource leak you point out is a serious bug.
Based on your finding the key issue here is that the job is not tracked properly. Instead of getting rid of the background loading could be make it into a proper cancellable job ( using I remember with BOY when the existing screen stayed visisble... instead of waiting users were inclined to keep pressing the button more and more - out of frustration - making matters worse. Again, we are quite glad you have discovered this |



Target branch:
ControlSystemStudio/phoebus:masterSource branch:
emilioheredia-source/phoebus:display/serialize-display-loadsDepends on: nothing
Summary
DisplayRuntimeInstance.loadDisplayFile()disposes the display that is shown, then loads the new one in a background job. A load that is still in its job is not tracked anywhere until its display is represented. When a second load starts in that time, nothing disposes the first one, and its job still represents the display and starts its runtime. Two things go wrong:Closing the display while a load is running has a related problem: the load continues, and a "Cannot load model" error appears after the display is gone, together with an
IllegalArgumentException: Expecting Group or Pane, got nullon the UI thread.A double click on the toolbar's "back" button is enough to hit it. Large displays, which take longer to load, make it more likely. With a display of about 300 widgets, two clicks 30 ms apart left all 21 PVs of the skipped display connected (checked in the PV pool's log).
With this PR, loads of a display instance run one at a time, up to the start of their runtime:
Restoring 15 example displays in 3 windows at startup takes the same time as on master (see the comment below for the numbers).
To keep
loadDisplayFile()readable, the body of the background job is split into a few helpers. Apart from the dispose step and the checks above, the code is unchanged;git diff -wshows the actual change.Not covered here: the "replace" target of an Open Display action doesn't go through
loadDisplayFile(). It replaces the representation directly on the UI thread.Testing
Checklist
DisplayLoadSequenceUI: two loads in a row, a replaced load that fails, closing a display while it loads; all three fail on master)-Dtestfx.robot=glassunder Xvfb)The TestFX test follows the
*UInaming of theui-testsprofile. That profile currently runs no tests: failsafe 2.22.0 fails to discover JUnit 5 tests with the current JUnit platform (NoSuchMethodError ... getDiscoveryListener()), also for the existing UI tests incore/ui. So for now the test was run with surefire, as above.