Add benchmark for Or selector and avoid extra virtual calls getting list count.

This commit is contained in:
Dariusz Komosinski
2023-03-05 17:49:45 +01:00
parent cea3496341
commit d9d208b935
5 changed files with 76 additions and 25 deletions
@@ -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/>
+11 -16
View File
@@ -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)
@@ -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/>
@@ -0,0 +1,15 @@
{
"profiles": {
"Avalonia.Benchmarks": {
"commandName": "Project"
},
"Avalonia.Benchmarks (in-process)": {
"commandName": "Project",
"commandLineArgs": "--inprocess"
},
"Avalonia.Benchmarks (debug)": {
"commandName": "Project",
"commandLineArgs": "--debug"
}
}
}
@@ -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;
}
}