-
Notifications
You must be signed in to change notification settings - Fork 437
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
8322964: Optimize performance of CSS selector matching #1316
base: master
Are you sure you want to change the base?
8322964: Optimize performance of CSS selector matching #1316
Conversation
👋 Welcome back jhendrikx! A progress list of the required criteria for merging this PR into |
Webrevs
|
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.
I just scrolled quickly through the changes and left some comments,
If deprecation for removal is part of the PR the consequences will need to be discussed. Are the for-removal classes and methods not widely used?
modules/javafx.graphics/src/main/java/com/sun/javafx/css/FixedCapacitySet.java
Outdated
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/javafx/css/SimpleSelector.java
Outdated
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/javafx/css/SimpleSelector.java
Outdated
Show resolved
Hide resolved
As @nlisker notes, the implications of any deprecation will need to be discussed. In particular, we need to consider what the consequences are for existing applications. If any of them might be used by apps, then simple deprecation (rather than deprecating for removal) might be best. /reviewers 3 |
@kevinrushforth |
@kevinrushforth has indicated that a compatibility and specification (CSR) request is needed for this pull request. @hjohn please create a CSR request for issue JDK-8322964 with the correct fix version. This pull request cannot be integrated until the CSR request is approved. |
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.
Left a couple inline comments.
modules/javafx.graphics/src/main/java/javafx/css/SimpleSelector.java
Outdated
Show resolved
Hide resolved
modules/javafx.graphics/src/main/java/com/sun/javafx/css/FixedCapacitySet.java
Show resolved
Hide resolved
The methods cannot be reached easily even though they are public. It would involve creating a The only use of one of the deprecated methods is to allow access for the internal class Google searches turn up no hits in 3rd party code for either of these. I've posted on the mailing list to discuss it further. |
Mailing list message from Dirk Lemmermann on openjfx-dev: I truly love the fact that you guys are starting to use JFXCentral for benchmarking / testing :-) If anyone encounters things bad for performance unrelated to JavaFX itself but caused by JFXCentral then please let me know. Dirk |
Mailing list message from John Hendrikx on openjfx-dev: It's a very nice application, I had never seen it before.? As the I'll let you know if I discover that's off.? Only thing I did was --John On 04/01/2024 22:49, Dirk Lemmermann wrote:
|
public static <T> FixedCapacitySet<T> of(int maximumCapacity) { | ||
return maximumCapacity == 0 ? empty() | ||
: maximumCapacity == 1 ? new Single<>() | ||
: maximumCapacity == 2 ? new Duo<>() |
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.
I can confirm that most of the code in my application uses 1-2 styleclasses.
Since all controls have one styleclass by default (some even more, think about TextInputControl
with text-input
-> TextField
with text-field
), does it make sense to also implement a specialized Triple
class?
We also often add 2 more styleclasses, so 3 style classes seems like a usecase that happens quite often.
I also can confirm that 4 styleclasses or even more are very rare.
I only found one: (.label
+ 3 added from us)
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.
Thanks for having a look, it's good to have some more use cases from other applications! The sets are used both for the style classes on Node
s but also the set of style classes in CSS selectors (multiple style classes in selectors are even more rare I think than multiple style classes on Node
s).
I think from a performance perspective, Duo
and Hashless
are likely very closely matched, but I can do some testing in that area. The reason I say this is that I only got a very minor boost from including Duo
, but kept it because it is a bit more memory efficient.
If you want, I'm also curious about how many styles are used in your application (you can see this by looking at the size of StyleClassSet#styleClasses
after all styles are loaded).
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.
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.
Thanks, it looks like a bit less classes are in use when compared to JFXCentral (which has about 1000), but still quite a lot. With BitSet
that means if style classes are referenced that happen to have a high bit set, it creates an array to hold 400 bits (using 8 longs). When few style classes are active, the sets provided by FixedCapacitySet
will be often smaller and (due to the other optimizations as well) faster. 8 longs is sufficient to hold 8 or 16 style name references depending on the JVM (32/64 bit, compressed pointers y/n).
@hjohn This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
I think this PR now no longer needs a CSR. |
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.
looks good to me.
how do we undo the csr command?
modules/javafx.graphics/src/main/java/com/sun/javafx/css/FixedCapacitySet.java
Show resolved
Hide resolved
I think its /csroff or something... |
/csroff |
@hjohn Unknown command |
/csr unneeded |
I was about to reply, but I see that the Skara bot beat me to it. :) I'll double-check later (or Andy can), and if there are no public API implications, issue the |
@hjohn is right - no public API changes remain in this PR. |
/csr unneeded |
@andy-goryachev-oracle determined that a CSR request is not needed for this pull request. |
@hjohn This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 89 new 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 this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
@hjohn This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
I think this is ready to be integrated. Let me know if there is anything still missing. |
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.
Looks good to me.
|
||
/* | ||
* Copied from removed StyleClassSet to give StyleClasses a fixed index when | ||
* first encountered. No longer needed once StyleClass is removed. |
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.
Is this a possible idea for the future?
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.
Yes, once this class is moved to private API (see #1333) then this method can be removed. The SimpleSelector
class is already deprecated for removal since 23.
The method is almost impossible to reach (you'd have to cast to SimpleSelector
), but removing it as part of this PR would have required a CSR making this harder to integrate.
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.
Code looks good to me. As mentioned above, I tested it already and everything was good, so I'm certain that there is no regression here.
I'm generally not a big fan of 'reimplementing' Collections, but I can see why it is needed here and it also makes sense, especially for something like CSS which needs to be fast.
Something I saw as well in Swing (just check the ArrayTable
class 😄 ).
I wonder if we may want to add some tests for the FixedCapacitySet
?
I'm in the process of testing this. I'll do that and report back. |
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.
Code looks good. Testing looks good.
I'm not a fan either, especially because custom collection implementations when referred to by their interface may sneak their way through the various classes and eventually be returned to users. Any deviation from the collection contracts then suddenly is a bug users may encounter. I would have done this with plain
Yeah, now that it is more likely that this will make it into FX, I will add a small set of unit tests for this class. |
Since this PR is ready to integrate, I think it would be fine to file a new test bug for the additional tests if you like. If you prefer to add the new tests now, that's fine, too (we can re-review it). |
I'm fine integrating this as-is and adding a test soon after. I will leave this over the weekend to give others time to review. Also some clarification on the contributing rules: "all Reviewers who have requested the chance to review have done so" -- does the indication at the top right of the PR count towards this or should it be a comment? :) In the first case, @nlisker and @arapte, please indicate if you wish to review this still. |
The code looks good. I didn't test it, but I'm fine with integrating. |
I built it and tested on a retail self-checkout app that uses a lot of css. All good. |
If someone wants you to wait for them, they should make it clear by adding a comment. Also if someone has given substantive feedback, but hasn't (re)approved, it's good to give them a change to review. @arapte can add a comment if he wants to review, otherwise go ahead and integrate on Monday. |
Improves performance of selector matching in the CSS subsystem. This is done by using custom set implementation which are highly optimized for the most common cases where the number of selectors is small (most commonly 1 or 2). It also should be more memory efficient for medium sized and large applications which have many style names defined in various CSS files.
Due to the optimization, the concept of
StyleClass
, which was only introduced to assign a fixed bit index for each unique style class name encountered, is no longer needed. This is because style classes are no longer stored in aBitSet
which required a fixed index per encountered style class.The performance improvements are the result of several factors:
BitSet
for potentially 1000 different style names needed 1000 bits (worst case) as it was not sparse).containsAll
check thanks to the inverse functionisSuperSetOf
StyleClass
and put them into aSet
) -- this copy could not be cached and was always discarded immediately after...The overall performance was tested using the JFXCentral application which displays about 800 nodes on its start page with about 1000 styles in various style sheets (and which allows to refresh this page easily).
On JavaFX 20, the fastest refresh speed was 121 ms on my machine. With the improvements in this PR, the fastest refresh had become 89 ms. The speed improvement is the result of a 30% faster
Scene#doCSSPass
, which takes up the bulk of the time to refresh the JFXCentral main page (about 100 ms before vs 70 ms after the change).Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1316/head:pull/1316
$ git checkout pull/1316
Update a local copy of the PR:
$ git checkout pull/1316
$ git pull https://git.openjdk.org/jfx.git pull/1316/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1316
View PR using the GUI difftool:
$ git pr show -t 1316
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1316.diff
Webrev
Link to Webrev Comment