Performance issues caused by the styling system
See original GitHub issueWhen working on optimizing responsiveness of my project I’ve noticed worrying patterns that show when profiling.
Class selectors are viral and attach to all controls
Selectors in the main theme (fluent for example) like https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Themes.Fluent/DatePicker.xaml#L89 end up being added to all RepeatButton
instances. This wouldn’t be a huge problem but there is another problem
Style setters are evaluated instantly
Said RepeatButton
style has Content
property setter: https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Themes.Fluent/DatePicker.xaml#L95-L101
This means that every time RepeatButton
gets styled this content template will be evaluated, control tree built, path geometry will be parsed and constructed. So detaching and attaching control again will cause this to be built again. When one is creating a lot of such controls dynamically it ends up being fairly noticeable when profiling.
Another kind of setters are the ones that use resources: https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Themes.Fluent/DatePicker.xaml#L94
Such setter will resolve SystemControlBackgroundChromeMediumLowBrush
and subscribe to changes (which is not cheap since resource system has to traverse entire tree upwards to find it).
And styles generally have several such setters so it starts to add up and performance starts to degrade.
Important fact is that this style has built a content template and resolved several resources without matching. This style has no effect and in most of the cases it will never be applied. Yet everybody has to pay the price.
Such setup is making Avalonia applications feel sluggish and not responsive when new content is being added. In our case we are already careful and virtualize/recycle as much as possible but still certain content is dynamic and we end up freezing the application when styles are applied. Such slowdowns take usually less than 100ms but if we are rendering at 60 FPS this means we just skipped 6 frames applying styles and user definitely noticed it.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:5
- Comments:20 (20 by maintainers)
I think we can close this now that #8263 has been merged!
Selector can have restricted functionality. But I would definitely not change the syntax. Just require Selector to support only types.
There are directly equivalents for both in WPF/UWP so this isn’t a new idea. See the table below summarizing all ideas.
There would be no issue here as far as I can see. We all agree in the base case that Selector is equivalent to TargetType. Therefore, Selector type is matched first, then the key is matched. If you specify a key with an incompatible type an exception is thrown. Again, this is no different than WPF/UWP. In other words, the same key can be used to reference this style anywhere the type is Menu or MenuItem (or a derivative thereorof). So it is usable for both and I don’t think we would ever need to make the assumption you mention.
It wouldn’t do anything for load times, yes, but evaluation of selectors would be much quicker. Children are only evaluated if the parent matches. Setters are ignored entirely for all the secondary state styles (pressed, etc.) except for the precise controls that need them. As I understand it that is the majority of the performance issue.