-
Notifications
You must be signed in to change notification settings - Fork 542
8246745: ListCell/Skin: misbehavior on switching skin #251
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
Conversation
|
👋 Welcome back fastegal! A progress list of the required criteria for merging this PR into |
Webrevs
|
|
@arapte can you review? |
| @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { | ||
| if (fixedCellSizeEnabled) { | ||
| double fixedCellSize = getFixedCellSize(); | ||
| if (fixedCellSize > 0) { |
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.
These compute methods get invoked multiple times during each layout pass(10s of times). Fetching the fixed cell size on each call to these methods seems to be repeated and costly operation compared to previous boolean check. I think we should keep the previous way of handling it: registering the change listener to listView.fixedCellSizeProperty().
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.
ehh .. last time I did such micro-optimization was in the 80ies of last century ;)
Are there any performance measurements anywhere to demonstrate the impact?
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.
a bit less flippant: really interested in the measurements - certainly, they are somewhere but can't find anything. Any pointer where to look?
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.
Even I do not know if there are any performance measurements for such scenario. :) May be @kevinrushforth could help in that.
I just counted the calls by adding a log, and observed that for a ListView with only one item, these three methods combinely are called 23 times when the Stage is displayed for the first time and 5 times when the item is selected. (updated the counts after rechecking, looks like the methods are invoked for empty cells too, which seems correct)
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.
hmm, do you mean a list with height of one cell only?
My experiment (having counters per instance and per computeXXHeight), logs 1 (or 2) for computePref with fixed size and 5 (1 each for min/max and 3 for pref) without fixedSize per layout pass. So it's 5* access of either the local field or the listView method .. wouldn't expect any problems, but then assumed performance is reading in coffee ground :)
Let's hope there are some metrics to use :)
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.
hmm, do you mean a list with height of one cell only?
Yes, List with one cell height.
In continuation to my previous comment, looks like 8 of the first 23 calls when window is displayed for the first time are NOT for the one visible cell. These 8 calls are for some intermediate cell.
I added a single counter for all three computeXXHeight methods and verified with a list of height of one cell.
When fixedCellSize is not set, total combined number of calls for a cell are,
- 15, when Stage is displayed for the first time.(+8 for an intermediate cell, not sure why)
- 5, when the list item is selected.
- 5, when the Window is resized.
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.
something similar as I'm seeing - that's good :) Uploaded my play code to gist: the idea is to do something (like f.i. moving the selection), then press f1 to log the calls to each cell (the skin has a final instance counter and counters for calling the compute methods).
As much fun as this is (really like to dig until I'm dirty all over :) - at the end of the day we'll need some measurements (doing these is not so much fun, still hoping something already available)
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.
Normally we implement this sort of lazy evaluation (caching + invalidation) when there is a computation that is being saved, or when a micro-benchmark shows that something is called 1000s of times (e.g., in the inner loop of some common operation).
I don't see either being the case here, but it's possible I missed something. The method in question, getFixedCellSize() just calls ListView::getFixedCellSize which just returns the value of a property. I suspect that any performance hit would be down in the noise.
So I think the complexity of the existing mechanism isn't justified. Removing the listener as the PR proposes to do, which is possible since the listener isn't being used to trigger an operation, seems like a win as well.
I am inclined to approve this fix even without performance measurements, since it seems unlikely they would show a problem.
@arapte if you want to measure it further before you approve it, that would be fine.
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.
The few additional computation would not cause any harm to performance. It just increases few computations in the compute* methods. Just for sanity verified a program with ListView of 10000000. ListView gets scrolled just as smooth.
Approving.
|
Hmm .. bottleneck seems to be layout as such (including css), accessing an instance field vs. querying a property doesn't make a difference (at least none I could see). |
|
/reviewers 2 |
|
@kevinrushforth |
kevinrushforth
left a comment
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.
(catching up on some overdue reviews)
The fix and tests look fine to me. I left one minor suggestion to add a comment in one of the tests.
| @Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) { | ||
| if (fixedCellSizeEnabled) { | ||
| double fixedCellSize = getFixedCellSize(); | ||
| if (fixedCellSize > 0) { |
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.
Normally we implement this sort of lazy evaluation (caching + invalidation) when there is a computation that is being saved, or when a micro-benchmark shows that something is called 1000s of times (e.g., in the inner loop of some common operation).
I don't see either being the case here, but it's possible I missed something. The method in question, getFixedCellSize() just calls ListView::getFixedCellSize which just returns the value of a property. I suspect that any performance hit would be down in the noise.
So I think the complexity of the existing mechanism isn't justified. Removing the listener as the PR proposes to do, which is possible since the listener isn't being used to trigger an operation, seems like a win as well.
I am inclined to approve this fix even without performance measurements, since it seems unlikely they would show a problem.
@arapte if you want to measure it further before you approve it, that would be fine.
modules/javafx.controls/src/test/java/test/javafx/scene/control/skin/SkinCleanupTest.java
Show resolved
Hide resolved
|
@kleopatra This change now passes all automated pre-integration checks. In addition to the automated checks, the change must also fulfill all project specific requirements After integration, the commit message will be:
Since the source branch of this PR was last updated there have been 74 commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid automatic rebasing, please merge ➡️ To integrate this PR with the above commit message to the |
|
/integrate |
|
@kleopatra Since your change was applied there have been 74 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit 0514116. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
ListCellSkin installs listeners to the ListView/fixedCellSize that introduce a memory leak, NPE on replacing the listView and incorrect update of internal state (see bug report for details)
Fixed by removing the listeners (and the internal state had been copied from listView on change) and access of listView state when needed.
Added tests that failed before and pass after the fix, plus a sanity test to guarantee same (correct) behavior before/after.
Progress
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jfx pull/251/head:pull/251$ git checkout pull/251