Browse Source

Merge pull request #10560 from MarchingCube/selector-perf

Or Selector benchmark and removal of repeated virtual calls
gh-readonly-queue/master/pr-10559-10fe00655310a09f8d306cd5ffeffb900759b68f
Max Katz 3 years ago
committed by GitHub
parent
commit
10fe006553
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Avalonia.Base/Styling/DescendentSelector.cs
  2. 27
      src/Avalonia.Base/Styling/OrSelector.cs
  3. 9
      src/Avalonia.Base/Styling/TypeNameAndClassSelector.cs
  4. 15
      tests/Avalonia.Benchmarks/Properties/launchSettings.json
  5. 48
      tests/Avalonia.Benchmarks/Styling/SelectorBenchmark.cs

2
src/Avalonia.Base/Styling/DescendentSelector.cs

@ -13,7 +13,7 @@ namespace Avalonia.Styling
public DescendantSelector(Selector? parent)
{
_parent = parent ?? throw new InvalidOperationException("Descendant selector must be preceeded by a selector.");
_parent = parent ?? throw new InvalidOperationException("Descendant selector must be preceded by a selector.");
}
/// <inheritdoc/>

27
src/Avalonia.Base/Styling/OrSelector.cs

@ -10,7 +10,7 @@ namespace Avalonia.Styling
/// <summary>
/// The OR style selector.
/// </summary>
internal class OrSelector : Selector
internal sealed class OrSelector : Selector
{
private readonly IReadOnlyList<Selector> _selectors;
private string? _selectorString;
@ -42,18 +42,7 @@ namespace Avalonia.Styling
public override bool IsCombinator => false;
/// <inheritdoc/>
public override Type? TargetType
{
get
{
if (_targetType == null)
{
_targetType = EvaluateTargetType();
}
return _targetType;
}
}
public override Type? TargetType => _targetType ??= EvaluateTargetType();
/// <inheritdoc/>
public override string ToString(Style? owner)
@ -71,7 +60,9 @@ namespace Avalonia.Styling
var activators = new OrActivatorBuilder();
var neverThisInstance = false;
for (var i = 0; i < _selectors.Count; i++)
var count = _selectors.Count;
for (var i = 0; i < count; i++)
{
var match = _selectors[i].Match(control, parent, subscribe);
@ -108,7 +99,9 @@ namespace Avalonia.Styling
internal override void ValidateNestingSelector(bool inControlTheme)
{
for (var i = 0; i < _selectors.Count; i++)
var count = _selectors.Count;
for (var i = 0; i < count; i++)
{
_selectors[i].ValidateNestingSelector(inControlTheme);
}
@ -118,7 +111,9 @@ namespace Avalonia.Styling
{
Type? result = null;
for (var i = 0; i < _selectors.Count; i++)
var count = _selectors.Count;
for (var i = 0; i < count; i++)
{
var selector = _selectors[i];
if (selector.TargetType == null)

9
src/Avalonia.Base/Styling/TypeNameAndClassSelector.cs

@ -11,7 +11,7 @@ namespace Avalonia.Styling
/// A selector that matches the common case of a type and/or name followed by a collection of
/// style classes and pseudoclasses.
/// </summary>
internal class TypeNameAndClassSelector : Selector
internal sealed class TypeNameAndClassSelector : Selector
{
private readonly Selector? _previous;
private List<string>? _classes;
@ -85,12 +85,7 @@ namespace Avalonia.Styling
/// <inheritdoc/>
public override string ToString(Style? owner)
{
if (_selectorString == null)
{
_selectorString = BuildSelectorString(owner);
}
return _selectorString;
return _selectorString ??= BuildSelectorString(owner);
}
/// <inheritdoc/>

15
tests/Avalonia.Benchmarks/Properties/launchSettings.json

@ -0,0 +1,15 @@
{
"profiles": {
"Avalonia.Benchmarks": {
"commandName": "Project"
},
"Avalonia.Benchmarks (in-process)": {
"commandName": "Project",
"commandLineArgs": "--inprocess"
},
"Avalonia.Benchmarks (debug)": {
"commandName": "Project",
"commandLineArgs": "--debug"
}
}
}

48
tests/Avalonia.Benchmarks/Styling/SelectorBenchmark.cs

@ -1,4 +1,5 @@
using Avalonia.Controls;
using System;
using Avalonia.Controls;
using Avalonia.Styling;
using BenchmarkDotNet.Attributes;
@ -11,6 +12,8 @@ namespace Avalonia.Benchmarks.Styling
private readonly Calendar _matchingControl;
private readonly Selector _isCalendarSelector;
private readonly Selector _classSelector;
private readonly Selector _orSelectorTwo;
private readonly Selector _orSelectorFive;
public SelectorBenchmark()
{
@ -23,6 +26,14 @@ namespace Avalonia.Benchmarks.Styling
_isCalendarSelector = Selectors.Is<Calendar>(null);
_classSelector = Selectors.Class(null, className);
_orSelectorTwo = Selectors.Or(new AlwaysMatchSelector(), new AlwaysMatchSelector());
_orSelectorFive = Selectors.Or(
new AlwaysMatchSelector(),
new AlwaysMatchSelector(),
new AlwaysMatchSelector(),
new AlwaysMatchSelector(),
new AlwaysMatchSelector());
}
[Benchmark]
@ -48,5 +59,40 @@ namespace Avalonia.Benchmarks.Styling
{
return _classSelector.Match(_matchingControl);
}
[Benchmark]
public SelectorMatch OrSelector_One_Match()
{
return _orSelectorTwo.Match(_matchingControl);
}
[Benchmark]
public SelectorMatch OrSelector_Five_Match()
{
return _orSelectorFive.Match(_matchingControl);
}
}
internal class AlwaysMatchSelector : Selector
{
public override bool InTemplate => false;
public override bool IsCombinator => false;
public override Type TargetType => null;
public override string ToString(Style owner)
{
return "Always";
}
protected override SelectorMatch Evaluate(StyledElement control, IStyle parent, bool subscribe)
{
return SelectorMatch.AlwaysThisType;
}
protected override Selector MovePrevious() => null;
protected override Selector MovePreviousOrParent() => null;
}
}

Loading…
Cancel
Save