فهرست منبع

Added additional benchmarks.

Testing performance of low-level mechanisms.
Steven Kirk 3 سال پیش
والد
کامیت
a0ec91ec01

+ 1 - 1
tests/Avalonia.Benchmarks/Avalonia.Benchmarks.csproj

@@ -19,7 +19,7 @@
     <ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
+    <PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Properties\" />

+ 149 - 0
tests/Avalonia.Benchmarks/Base/AvaloniaObject_Binding.cs

@@ -0,0 +1,149 @@
+using System.Runtime.CompilerServices;
+using Avalonia.Data;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Base
+{
+    [MemoryDiagnoser]
+    public class AvaloniaObject_Binding
+    {
+        private static TestClass _target = null!;
+        private static TestBindingObservable<string?> s_stringSource = new();
+        private static TestBindingObservable<Struct1> s_struct1Source = new();
+        private static TestBindingObservable<Struct2> s_struct2Source = new();
+        private static TestBindingObservable<Struct3> s_struct3Source = new();
+        private static TestBindingObservable<Struct4> s_struct4Source = new();
+        private static TestBindingObservable<Struct5> s_struct5Source = new();
+        private static TestBindingObservable<Struct6> s_struct6Source = new();
+        private static TestBindingObservable<Struct7> s_struct7Source = new();
+        private static TestBindingObservable<Struct8> s_struct8Source = new();
+
+        public AvaloniaObject_Binding()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            _target = new TestClass();
+        }
+
+        [Benchmark]
+        public void Setup_Dispose_LocalValue_Bindings()
+        {
+            var target = _target;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                using var s0 = target.Bind(TestClass.StringProperty, s_stringSource);
+                using var s1 = target.Bind(TestClass.Struct1Property, s_struct1Source);
+                using var s2 = target.Bind(TestClass.Struct2Property, s_struct2Source);
+                using var s3 = target.Bind(TestClass.Struct3Property, s_struct3Source);
+                using var s4 = target.Bind(TestClass.Struct4Property, s_struct4Source);
+                using var s5 = target.Bind(TestClass.Struct5Property, s_struct5Source);
+                using var s6 = target.Bind(TestClass.Struct6Property, s_struct6Source);
+                using var s7 = target.Bind(TestClass.Struct7Property, s_struct7Source);
+                using var s8 = target.Bind(TestClass.Struct8Property, s_struct8Source);
+            }
+        }
+
+
+        [Benchmark]
+        public void Fire_LocalValue_Bindings()
+        {
+            var target = _target;
+
+            using var s0 = target.Bind(TestClass.StringProperty, s_stringSource);
+            using var s1 = target.Bind(TestClass.Struct1Property, s_struct1Source);
+            using var s2 = target.Bind(TestClass.Struct2Property, s_struct2Source);
+            using var s3 = target.Bind(TestClass.Struct3Property, s_struct3Source);
+            using var s4 = target.Bind(TestClass.Struct4Property, s_struct4Source);
+            using var s5 = target.Bind(TestClass.Struct5Property, s_struct5Source);
+            using var s6 = target.Bind(TestClass.Struct6Property, s_struct6Source);
+            using var s7 = target.Bind(TestClass.Struct7Property, s_struct7Source);
+            using var s8 = target.Bind(TestClass.Struct8Property, s_struct8Source);
+
+            for (var i = 0; i < 100; ++i)
+            {
+                s_stringSource.OnNext(i.ToString());
+                s_struct1Source.OnNext(new(i + 1));
+                s_struct2Source.OnNext(new(i + 1));
+                s_struct3Source.OnNext(new(i + 1));
+                s_struct4Source.OnNext(new(i + 1));
+                s_struct5Source.OnNext(new(i + 1));
+                s_struct6Source.OnNext(new(i + 1));
+                s_struct7Source.OnNext(new(i + 1));
+                s_struct8Source.OnNext(new(i + 1));
+            }
+        }
+
+        [GlobalSetup(Target = nameof(Fire_LocalValue_Bindings_With_Style_Values))]
+        public void SetupStyleValues()
+        {
+            _target = new TestClass();
+            _target.SetValue(TestClass.StringProperty, "foo", BindingPriority.Style);
+            _target.SetValue(TestClass.Struct1Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct2Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct3Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct4Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct5Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct6Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct7Property, new(), BindingPriority.Style);
+            _target.SetValue(TestClass.Struct8Property, new(), BindingPriority.Style);
+        }
+
+        [Benchmark]
+        public void Fire_LocalValue_Bindings_With_Style_Values()
+        {
+            var target = _target;
+
+            using var s0 = target.Bind(TestClass.StringProperty, s_stringSource);
+            using var s1 = target.Bind(TestClass.Struct1Property, s_struct1Source);
+            using var s2 = target.Bind(TestClass.Struct2Property, s_struct2Source);
+            using var s3 = target.Bind(TestClass.Struct3Property, s_struct3Source);
+            using var s4 = target.Bind(TestClass.Struct4Property, s_struct4Source);
+            using var s5 = target.Bind(TestClass.Struct5Property, s_struct5Source);
+            using var s6 = target.Bind(TestClass.Struct6Property, s_struct6Source);
+            using var s7 = target.Bind(TestClass.Struct7Property, s_struct7Source);
+            using var s8 = target.Bind(TestClass.Struct8Property, s_struct8Source);
+
+            for (var i = 0; i < 100; ++i)
+            {
+                s_stringSource.OnNext(i.ToString());
+                s_struct1Source.OnNext(new(i + 1));
+                s_struct2Source.OnNext(new(i + 1));
+                s_struct3Source.OnNext(new(i + 1));
+                s_struct4Source.OnNext(new(i + 1));
+                s_struct5Source.OnNext(new(i + 1));
+                s_struct6Source.OnNext(new(i + 1));
+                s_struct7Source.OnNext(new(i + 1));
+                s_struct8Source.OnNext(new(i + 1));
+            }
+        }
+
+        private class TestClass : AvaloniaObject
+        {
+            public static readonly StyledProperty<string?> StringProperty =
+                AvaloniaProperty.Register<TestClass, string?>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+    }
+}

+ 81 - 0
tests/Avalonia.Benchmarks/Base/AvaloniaObject_Construct.cs

@@ -0,0 +1,81 @@
+using System.Runtime.CompilerServices;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Base
+{
+    [MemoryDiagnoser]
+    public class AvaloniaObject_Construct
+    {
+        public AvaloniaObject_Construct()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [Benchmark(Baseline = true)]
+        public void ConstructClrObject_And_Set_Values()
+        {
+            var target = new BaselineTestClass();
+            target.StringProperty = "foo";
+            target.Struct1Property = new(1);
+            target.Struct2Property = new(1);
+            target.Struct3Property = new(1);
+            target.Struct4Property = new(1);
+            target.Struct5Property = new(1);
+            target.Struct6Property = new(1);
+            target.Struct7Property = new(1);
+            target.Struct8Property = new(1);
+        }
+
+        [Benchmark]
+        public void Construct_And_Set_Values()
+        {
+            var target = new TestClass();
+            target.SetValue(TestClass.StringProperty, "foo");
+            target.SetValue(TestClass.Struct1Property, new(1));
+            target.SetValue(TestClass.Struct2Property, new(1));
+            target.SetValue(TestClass.Struct3Property, new(1));
+            target.SetValue(TestClass.Struct4Property, new(1));
+            target.SetValue(TestClass.Struct5Property, new(1));
+            target.SetValue(TestClass.Struct6Property, new(1));
+            target.SetValue(TestClass.Struct7Property, new(1));
+            target.SetValue(TestClass.Struct8Property, new(1));
+        }
+
+        private class TestClass : AvaloniaObject
+        {
+            public static readonly StyledProperty<string> StringProperty =
+                AvaloniaProperty.Register<TestClass, string>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+
+        private class BaselineTestClass
+        {
+            public string? StringProperty { get; set; }
+            public Struct1 Struct1Property { get; set; }
+            public Struct2 Struct2Property { get; set; }
+            public Struct3 Struct3Property { get; set; }
+            public Struct4 Struct4Property { get; set; }
+            public Struct5 Struct5Property { get; set; }
+            public Struct6 Struct6Property { get; set; }
+            public Struct7 Struct7Property { get; set; }
+            public Struct8 Struct8Property { get; set; }
+        }
+    }
+}

+ 171 - 0
tests/Avalonia.Benchmarks/Base/AvaloniaObject_GetObservable.cs

@@ -0,0 +1,171 @@
+using System;
+using System.Runtime.CompilerServices;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Base
+{
+    [MemoryDiagnoser]
+    public class AvaloniaObject_GetObservable
+    {
+        private TestClass _target = null!;
+        public static int result;
+
+        public AvaloniaObject_GetObservable()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            _target = new();
+        }
+
+        [Benchmark(Baseline = true)]
+        public void PropertyChangedSubscription()
+        {
+            var target = _target;
+
+            static void ChangeHandler(object? sender, AvaloniaPropertyChangedEventArgs e)
+            {
+                if (e.Property == TestClass.StringProperty)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<string?>)e;
+                    result += ev.NewValue.Value?.Length ?? 0;
+                }
+                else if (e.Property == TestClass.Struct1Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct1>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct2Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct2>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct3Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct3>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct4Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct4>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct5Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct5>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct6Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct6>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct7Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct7>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+                else if (e.Property == TestClass.Struct8Property)
+                {
+                    var ev = (AvaloniaPropertyChangedEventArgs<Struct8>)e;
+                    result += ev.NewValue.Value.Int1;
+                }
+            }
+
+            target.PropertyChanged += ChangeHandler;
+
+            // GetObservable fires with the initial value so to compare like-for-like we also need
+            // to get the initial value here.
+            result += target.GetValue(TestClass.StringProperty)?.Length ?? 0;
+            result += target.GetValue(TestClass.Struct1Property).Int1;
+            result += target.GetValue(TestClass.Struct2Property).Int1;
+            result += target.GetValue(TestClass.Struct3Property).Int1;
+            result += target.GetValue(TestClass.Struct4Property).Int1;
+            result += target.GetValue(TestClass.Struct5Property).Int1;
+            result += target.GetValue(TestClass.Struct6Property).Int1;
+            result += target.GetValue(TestClass.Struct7Property).Int1;
+            result += target.GetValue(TestClass.Struct8Property).Int1;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                target.SetValue(TestClass.StringProperty, "foo" + i);
+                target.SetValue(TestClass.Struct1Property, new(i + 1));
+                target.SetValue(TestClass.Struct2Property, new(i + 1));
+                target.SetValue(TestClass.Struct3Property, new(i + 1));
+                target.SetValue(TestClass.Struct4Property, new(i + 1));
+                target.SetValue(TestClass.Struct5Property, new(i + 1));
+                target.SetValue(TestClass.Struct6Property, new(i + 1));
+                target.SetValue(TestClass.Struct7Property, new(i + 1));
+                target.SetValue(TestClass.Struct8Property, new(i + 1));
+            }
+
+            target.PropertyChanged -= ChangeHandler;
+        }
+
+        [Benchmark]
+        public void GetObservables()
+        {
+            var target = _target;
+
+            var sub1 = target.GetObservable(TestClass.StringProperty).Subscribe(x => result += x?.Length ?? 0);
+            var sub2 = target.GetObservable(TestClass.Struct1Property).Subscribe(x => result += x.Int1);
+            var sub3 = target.GetObservable(TestClass.Struct2Property).Subscribe(x => result += x.Int1);
+            var sub4 = target.GetObservable(TestClass.Struct3Property).Subscribe(x => result += x.Int1);
+            var sub5 = target.GetObservable(TestClass.Struct4Property).Subscribe(x => result += x.Int1);
+            var sub6 = target.GetObservable(TestClass.Struct5Property).Subscribe(x => result += x.Int1);
+            var sub7 = target.GetObservable(TestClass.Struct6Property).Subscribe(x => result += x.Int1);
+            var sub8 = target.GetObservable(TestClass.Struct7Property).Subscribe(x => result += x.Int1);
+            var sub9 = target.GetObservable(TestClass.Struct8Property).Subscribe(x => result += x.Int1);
+
+            for (var i = 0; i < 100; ++i)
+            {
+                target.SetValue(TestClass.StringProperty, "foo" + i);
+                target.SetValue(TestClass.Struct1Property, new(i + 1));
+                target.SetValue(TestClass.Struct2Property, new(i + 1));
+                target.SetValue(TestClass.Struct3Property, new(i + 1));
+                target.SetValue(TestClass.Struct4Property, new(i + 1));
+                target.SetValue(TestClass.Struct5Property, new(i + 1));
+                target.SetValue(TestClass.Struct6Property, new(i + 1));
+                target.SetValue(TestClass.Struct7Property, new(i + 1));
+                target.SetValue(TestClass.Struct8Property, new(i + 1));
+            }
+
+            sub1.Dispose();
+            sub2.Dispose();
+            sub3.Dispose();
+            sub4.Dispose();
+            sub5.Dispose();
+            sub6.Dispose();
+            sub7.Dispose();
+            sub8.Dispose();
+            sub9.Dispose();
+        }
+
+        private class TestClass : AvaloniaObject
+        {
+            public static readonly StyledProperty<string> StringProperty =
+                AvaloniaProperty.Register<TestClass, string>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+    }
+}

+ 181 - 0
tests/Avalonia.Benchmarks/Base/AvaloniaObject_GetValue.cs

@@ -0,0 +1,181 @@
+using System.Runtime.CompilerServices;
+using Avalonia.Data;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Base
+{
+    [MemoryDiagnoser]
+    public class AvaloniaObject_GetValue
+    {
+        private BaselineTestClass _baseline = new(){ StringProperty = "foo" };
+        private TestClass _target = new();
+
+        public AvaloniaObject_GetValue()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [Benchmark(Baseline = true)]
+        public int GetClrPropertyValues()
+        {
+            var target = _baseline;
+            var result = 0;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                result += target.StringProperty?.Length ?? 0;
+                result += target.Struct1Property.Int1;
+                result += target.Struct2Property.Int1;
+                result += target.Struct3Property.Int1;
+                result += target.Struct4Property.Int1;
+                result += target.Struct5Property.Int1;
+                result += target.Struct6Property.Int1;
+                result += target.Struct7Property.Int1;
+                result += target.Struct8Property.Int1;
+            }
+
+            return result;
+        }
+
+        [Benchmark]
+        public int GetDefaultValues()
+        {
+            var target = _target;
+            var result = 0;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                result += target.GetValue(TestClass.StringProperty)?.Length ?? 0;
+                result += target.GetValue(TestClass.Struct1Property).Int1;
+                result += target.GetValue(TestClass.Struct2Property).Int1;
+                result += target.GetValue(TestClass.Struct3Property).Int1;
+                result += target.GetValue(TestClass.Struct4Property).Int1;
+                result += target.GetValue(TestClass.Struct5Property).Int1;
+                result += target.GetValue(TestClass.Struct6Property).Int1;
+                result += target.GetValue(TestClass.Struct7Property).Int1;
+                result += target.GetValue(TestClass.Struct8Property).Int1;
+            }
+
+            return result;
+        }
+
+        [GlobalSetup(Target = nameof(Get_Local_Values))]
+        public void SetupLocalValues()
+        {
+            _target.SetValue(TestClass.StringProperty, "foo");
+            _target.SetValue(TestClass.Struct1Property, new(1));
+            _target.SetValue(TestClass.Struct2Property, new(1));
+            _target.SetValue(TestClass.Struct3Property, new(1));
+            _target.SetValue(TestClass.Struct4Property, new(1));
+            _target.SetValue(TestClass.Struct5Property, new(1));
+            _target.SetValue(TestClass.Struct6Property, new(1));
+            _target.SetValue(TestClass.Struct7Property, new(1));
+            _target.SetValue(TestClass.Struct8Property, new(1));
+        }
+
+        [Benchmark]
+        public int Get_Local_Values()
+        {
+            var target = _target;
+            var result = 0;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                result += target.GetValue(TestClass.StringProperty)?.Length ?? 0;
+                result += target.GetValue(TestClass.Struct1Property).Int1;
+                result += target.GetValue(TestClass.Struct2Property).Int1;
+                result += target.GetValue(TestClass.Struct3Property).Int1;
+                result += target.GetValue(TestClass.Struct4Property).Int1;
+                result += target.GetValue(TestClass.Struct5Property).Int1;
+                result += target.GetValue(TestClass.Struct6Property).Int1;
+                result += target.GetValue(TestClass.Struct7Property).Int1;
+                result += target.GetValue(TestClass.Struct8Property).Int1;
+            }
+
+            return result;
+        }
+
+        [GlobalSetup(Target = nameof(Get_Local_Values_With_Style_Values))]
+        public void SetupLocalValuesAndStyleValues()
+        {
+            var target = _target;
+            target.SetValue(TestClass.StringProperty, "foo");
+            target.SetValue(TestClass.Struct1Property, new(1));
+            target.SetValue(TestClass.Struct2Property, new(1));
+            target.SetValue(TestClass.Struct3Property, new(1));
+            target.SetValue(TestClass.Struct4Property, new(1));
+            target.SetValue(TestClass.Struct5Property, new(1));
+            target.SetValue(TestClass.Struct6Property, new(1));
+            target.SetValue(TestClass.Struct7Property, new(1));
+            target.SetValue(TestClass.Struct8Property, new(1));
+            target.SetValue(TestClass.StringProperty, "bar", BindingPriority.Style);
+            target.SetValue(TestClass.Struct1Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct2Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct3Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct4Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct5Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct6Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct7Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct8Property, new(), BindingPriority.Style);
+        }
+
+        [Benchmark]
+        public int Get_Local_Values_With_Style_Values()
+        {
+            var target = _target;
+            var result = 0;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                result += target.GetValue(TestClass.StringProperty)?.Length ?? 0;
+                result += target.GetValue(TestClass.Struct1Property).Int1;
+                result += target.GetValue(TestClass.Struct2Property).Int1;
+                result += target.GetValue(TestClass.Struct3Property).Int1;
+                result += target.GetValue(TestClass.Struct4Property).Int1;
+                result += target.GetValue(TestClass.Struct5Property).Int1;
+                result += target.GetValue(TestClass.Struct6Property).Int1;
+                result += target.GetValue(TestClass.Struct7Property).Int1;
+                result += target.GetValue(TestClass.Struct8Property).Int1;
+            }
+
+            return result;
+        }
+
+        private class TestClass : AvaloniaObject
+        {
+            public static readonly StyledProperty<string> StringProperty =
+                AvaloniaProperty.Register<TestClass, string>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+
+        private class BaselineTestClass
+        {
+            public string? StringProperty { get; set; }
+            public Struct1 Struct1Property { get; set; }
+            public Struct2 Struct2Property { get; set; }
+            public Struct3 Struct3Property { get; set; }
+            public Struct4 Struct4Property { get; set; }
+            public Struct5 Struct5Property { get; set; }
+            public Struct6 Struct6Property { get; set; }
+            public Struct7 Struct7Property { get; set; }
+            public Struct8 Struct8Property { get; set; }
+        }
+    }
+}

+ 95 - 0
tests/Avalonia.Benchmarks/Base/AvaloniaObject_GetValueInherited.cs

@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Base
+{
+    [MemoryDiagnoser]
+    public class AvaloniaObject_GetValueInherited
+    {
+        private TestClass _root = null!;
+        private TestClass _target = null!;
+
+        public AvaloniaObject_GetValueInherited()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [Params(1, 2, 10, 50, 100, 200)]
+        public int Depth { get; set; }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            _root = new();
+            _root.SetValue(TestClass.StringProperty, "foo");
+            _root.SetValue(TestClass.Struct1Property, new(1));
+            _root.SetValue(TestClass.Struct2Property, new(1));
+            _root.SetValue(TestClass.Struct3Property, new(1));
+            _root.SetValue(TestClass.Struct4Property, new(1));
+            _root.SetValue(TestClass.Struct5Property, new(1));
+            _root.SetValue(TestClass.Struct6Property, new(1));
+            _root.SetValue(TestClass.Struct7Property, new(1));
+            _root.SetValue(TestClass.Struct8Property, new(1));
+
+            var parent = _root;
+
+            for (var i = 0; i < Depth; ++i)
+            {
+                var c = new TestClass();
+                ((ISetLogicalParent)c).SetParent(parent);
+                parent = c;
+            }
+
+            _target = parent;
+        }
+
+        [Benchmark]
+        public int GetInheritedValues()
+        {
+            var target = _target;
+            var result = 0;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                result += target.GetValue(TestClass.StringProperty)?.Length ?? 0;
+                result += target.GetValue(TestClass.Struct1Property).Int1;
+                result += target.GetValue(TestClass.Struct2Property).Int1;
+                result += target.GetValue(TestClass.Struct3Property).Int1;
+                result += target.GetValue(TestClass.Struct4Property).Int1;
+                result += target.GetValue(TestClass.Struct5Property).Int1;
+                result += target.GetValue(TestClass.Struct6Property).Int1;
+                result += target.GetValue(TestClass.Struct7Property).Int1;
+                result += target.GetValue(TestClass.Struct8Property).Int1;
+            }
+
+            return result;
+        }
+
+        private class TestClass : Control
+        {
+            public static readonly StyledProperty<string> StringProperty =
+                AvaloniaProperty.Register<TestClass, string>("String", inherits: true);
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1", inherits: true);
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2", inherits: true);
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3", inherits: true);
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4", inherits: true);
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5", inherits: true);
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6", inherits: true);
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7", inherits: true);
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8", inherits: true);
+        }
+    }
+}

+ 130 - 0
tests/Avalonia.Benchmarks/Base/AvaloniaObject_SetValue.cs

@@ -0,0 +1,130 @@
+using System.Runtime.CompilerServices;
+using Avalonia.Data;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Base
+{
+    [MemoryDiagnoser]
+    public class AvaloniaObject_SetValue
+    {
+        private BaselineTestClass _baseline = new();
+        private TestClass _target = new();
+
+        public AvaloniaObject_SetValue()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [Benchmark(Baseline = true)]
+        public int SetClrPropertyValues()
+        {
+            var target = _baseline;
+            var result = 0;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                target.StringProperty = "foo";
+                target.Struct1Property = new(i + 1);
+                target.Struct2Property = new(i + 1);
+                target.Struct3Property = new(i + 1);
+                target.Struct4Property = new(i + 1);
+                target.Struct5Property = new(i + 1);
+                target.Struct6Property = new(i + 1);
+                target.Struct7Property = new(i + 1);
+                target.Struct8Property = new(i + 1);
+            }
+
+            return result;
+        }
+
+        [Benchmark]
+        public void SetValues()
+        {
+            var target = _target;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                target.SetValue(TestClass.StringProperty, "foo");
+                target.SetValue(TestClass.Struct1Property, new(i + 1));
+                target.SetValue(TestClass.Struct2Property, new(i + 1));
+                target.SetValue(TestClass.Struct3Property, new(i + 1));
+                target.SetValue(TestClass.Struct4Property, new(i + 1));
+                target.SetValue(TestClass.Struct5Property, new(i + 1));
+                target.SetValue(TestClass.Struct6Property, new(i + 1));
+                target.SetValue(TestClass.Struct7Property, new(i + 1));
+                target.SetValue(TestClass.Struct8Property, new(i + 1));
+            }
+        }
+
+        [GlobalSetup(Target = nameof(Set_Local_Values_With_Style_Values))]
+        public void SetupStyleValues()
+        {
+            var target = _target;
+            target.SetValue(TestClass.StringProperty, "foo", BindingPriority.Style);
+            target.SetValue(TestClass.Struct1Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct2Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct3Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct4Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct5Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct6Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct7Property, new(), BindingPriority.Style);
+            target.SetValue(TestClass.Struct8Property, new(), BindingPriority.Style);
+        }
+
+        [Benchmark]
+        public void Set_Local_Values_With_Style_Values()
+        {
+            var target = _target;
+
+            for (var i = 0; i < 100; ++i)
+            {
+                target.SetValue(TestClass.StringProperty, "foo");
+                target.SetValue(TestClass.Struct1Property, new(i + 1));
+                target.SetValue(TestClass.Struct2Property, new(i + 1));
+                target.SetValue(TestClass.Struct3Property, new(i + 1));
+                target.SetValue(TestClass.Struct4Property, new(i + 1));
+                target.SetValue(TestClass.Struct5Property, new(i + 1));
+                target.SetValue(TestClass.Struct6Property, new(i + 1));
+                target.SetValue(TestClass.Struct7Property, new(i + 1));
+                target.SetValue(TestClass.Struct8Property, new(i + 1));
+            }
+        }
+
+        private class TestClass : AvaloniaObject
+        {
+            public static readonly StyledProperty<string> StringProperty =
+                AvaloniaProperty.Register<TestClass, string>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+
+        private class BaselineTestClass
+        {
+            public string? StringProperty { get; set; }
+            public Struct1 Struct1Property { get; set; }
+            public Struct2 Struct2Property { get; set; }
+            public Struct3 Struct3Property { get; set; }
+            public Struct4 Struct4Property { get; set; }
+            public Struct5 Struct5Property { get; set; }
+            public Struct6 Struct6Property { get; set; }
+            public Struct7 Struct7Property { get; set; }
+            public Struct8 Struct8Property { get; set; }
+        }
+    }
+}

+ 11 - 3
tests/Avalonia.Benchmarks/Base/DirectPropertyBenchmark.cs

@@ -1,14 +1,22 @@
-using BenchmarkDotNet.Attributes;
+using System.Runtime.CompilerServices;
+using BenchmarkDotNet.Attributes;
 
 namespace Avalonia.Benchmarks.Base
 {
     [MemoryDiagnoser]
     public class DirectPropertyBenchmark
     {
+        private DirectClass _target = new();
+
+        public DirectPropertyBenchmark()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(DirectClass).TypeHandle);
+        }
+
         [Benchmark(Baseline = true)]
         public void SetAndRaiseOriginal()
         {
-            var obj = new DirectClass();
+            var obj = _target;
 
             for (var i = 0; i < 100; ++i)
             {
@@ -19,7 +27,7 @@ namespace Avalonia.Benchmarks.Base
         [Benchmark]
         public void SetAndRaiseSimple()
         {
-            var obj = new DirectClass();
+            var obj = _target;
 
             for (var i = 0; i < 100; ++i)
             {

+ 65 - 0
tests/Avalonia.Benchmarks/Styling/Style_Activation.cs

@@ -0,0 +1,65 @@
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using Avalonia.Styling;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Styling
+{
+    [MemoryDiagnoser]
+    public class Style_Activation
+    {
+        private TestClass _target = null!;
+
+        public Style_Activation()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            _target = new TestClass();
+
+            var style = new Style(x => x.OfType<TestClass>().Class("foo"))
+            {
+                Setters = { new Setter(TestClass.StringProperty, "foo") }
+            };
+
+            style.TryAttach(_target, null);
+        }
+
+        [Benchmark]
+        public void Toggle_Style_Activation_Via_Class()
+        {
+            for (var i = 0; i < 100; ++i)
+            {
+                _target.Classes.Add("foo");
+                _target.Classes.Remove("foo");
+            }
+        }
+
+        private class TestClass : Control
+        {
+            public static readonly StyledProperty<string?> StringProperty =
+                AvaloniaProperty.Register<TestClass, string?>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+    }
+}

+ 89 - 0
tests/Avalonia.Benchmarks/Styling/Style_Apply.cs

@@ -0,0 +1,89 @@
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using Avalonia.Styling;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Styling
+{
+    [MemoryDiagnoser]
+    public class Style_Apply
+    {
+        private List<Style> _styles = new();
+
+        public Style_Apply()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [Params(1, 5, 50)]
+        public int MatchingStyles { get; set; }
+
+
+        [Params(1, 5, 50)]
+        public int NonMatchingStyles { get; set; }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            _styles.Clear();
+
+            for (var i = 0; i < MatchingStyles; ++i)
+            {
+                _styles.Add(new Style(x => x.OfType<TestClass>())
+                {
+                    Setters = { new Setter(TestClass.StringProperty, "foo") }
+                });
+            }
+
+            for (var i = 0; i < NonMatchingStyles; ++i)
+            {
+                _styles.Add(new Style(x => x.OfType<TestClass2>().Class("missing"))
+                {
+                    Setters = { new Setter(TestClass.StringProperty, "foo") }
+                });
+            }
+        }
+
+        [Benchmark]
+        public void Apply_Simple_Styles()
+        {
+            var target = new TestClass();
+
+            target.BeginBatchUpdate();
+
+            foreach (var style in _styles)
+                style.TryAttach(target, null);
+
+            target.EndBatchUpdate();
+        }
+
+        private class TestClass : Control
+        {
+            public static readonly StyledProperty<string?> StringProperty =
+                AvaloniaProperty.Register<TestClass, string?>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+
+        private class TestClass2 : Control
+        {
+        }
+    }
+}

+ 74 - 0
tests/Avalonia.Benchmarks/Styling/Style_NonActive.cs

@@ -0,0 +1,74 @@
+using System.Runtime.CompilerServices;
+using Avalonia.Controls;
+using Avalonia.Styling;
+using BenchmarkDotNet.Attributes;
+
+#nullable enable
+
+namespace Avalonia.Benchmarks.Styling
+{
+    [MemoryDiagnoser]
+    public class Style_NonActive
+    {
+        private TestClass _target = null!;
+
+        public Style_NonActive()
+        {
+            RuntimeHelpers.RunClassConstructor(typeof(TestClass).TypeHandle);
+        }
+
+        [GlobalSetup]
+        public void Setup()
+        {
+            _target = new TestClass();
+
+            var style = new Style(x => x.OfType<TestClass>().Class("foo"))
+            {
+                Setters = { new Setter(TestClass.StringProperty, "foo") }
+            };
+
+            style.TryAttach(_target, null);
+            _target.SetValue(TestClass.StringProperty, "foo");
+            _target.SetValue(TestClass.Struct1Property, new(1));
+            _target.SetValue(TestClass.Struct2Property, new(1));
+            _target.SetValue(TestClass.Struct3Property, new(1));
+            _target.SetValue(TestClass.Struct4Property, new(1));
+            _target.SetValue(TestClass.Struct5Property, new(1));
+            _target.SetValue(TestClass.Struct6Property, new(1));
+            _target.SetValue(TestClass.Struct7Property, new(1));
+            _target.SetValue(TestClass.Struct8Property, new(1));
+        }
+
+        [Benchmark]
+        public void Toggle_NonActive_Style_Activation()
+        {
+            for (var i = 0; i < 100; ++i)
+            {
+                _target.Classes.Add("foo");
+                _target.Classes.Remove("foo");
+            }
+        }
+
+        private class TestClass : Control
+        {
+            public static readonly StyledProperty<string?> StringProperty =
+                AvaloniaProperty.Register<TestClass, string?>("String");
+            public static readonly StyledProperty<Struct1> Struct1Property =
+                AvaloniaProperty.Register<TestClass, Struct1>("Struct1");
+            public static readonly StyledProperty<Struct2> Struct2Property =
+                AvaloniaProperty.Register<TestClass, Struct2>("Struct2");
+            public static readonly StyledProperty<Struct3> Struct3Property =
+                AvaloniaProperty.Register<TestClass, Struct3>("Struct3");
+            public static readonly StyledProperty<Struct4> Struct4Property =
+                AvaloniaProperty.Register<TestClass, Struct4>("Struct4");
+            public static readonly StyledProperty<Struct5> Struct5Property =
+                AvaloniaProperty.Register<TestClass, Struct5>("Struct5");
+            public static readonly StyledProperty<Struct6> Struct6Property =
+                AvaloniaProperty.Register<TestClass, Struct6>("Struct6");
+            public static readonly StyledProperty<Struct7> Struct7Property =
+                AvaloniaProperty.Register<TestClass, Struct7>("Struct7");
+            public static readonly StyledProperty<Struct8> Struct8Property =
+                AvaloniaProperty.Register<TestClass, Struct8>("Struct8");
+        }
+    }
+}

+ 38 - 0
tests/Avalonia.Benchmarks/TestBindingObservable.cs

@@ -0,0 +1,38 @@
+using System;
+using Avalonia.Data;
+
+namespace Avalonia.Benchmarks
+{
+    internal class TestBindingObservable<T> : IObservable<BindingValue<T?>>, IDisposable
+    {
+        private T? _value;
+        private IObserver<BindingValue<T?>>? _observer;
+
+        public TestBindingObservable(T? initialValue = default) => _value = initialValue;
+
+        public IDisposable Subscribe(IObserver<BindingValue<T?>> observer)
+        {
+            if (_observer is object)
+                throw new InvalidOperationException("The observable can only be subscribed once.");
+
+            _observer = observer;
+            observer.OnNext(_value);
+            return this;
+        }
+
+        public void Dispose() => _observer = null;
+        public void OnNext(T? value) => _observer?.OnNext(value);
+
+        public void PublishCompleted()
+        {
+            _observer?.OnCompleted();
+            _observer = null;
+        }
+
+        protected void PublishError(Exception error)
+        {
+            _observer?.OnError(error);
+            _observer = null;
+        }
+    }
+}

+ 112 - 0
tests/Avalonia.Benchmarks/TestTypes.cs

@@ -0,0 +1,112 @@
+using System;
+
+namespace Avalonia.Benchmarks
+{
+    internal record struct Struct1
+    {
+        public Struct1(int value)
+        {
+            Int1 = value;
+        }
+
+        public int Int1;
+    }
+
+    internal record struct Struct2
+    {
+        public Struct2(int value)
+        {
+            Int1 = Int2 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+    }
+
+    internal record struct Struct3
+    {
+        public Struct3(int value)
+        {
+            Int1 = Int2 = Int3 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+        public int Int3;
+    }
+
+    internal record struct Struct4
+    {
+        public Struct4(int value)
+        {
+            Int1 = Int2 = Int3 = Int4 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+        public int Int3;
+        public int Int4;
+    }
+
+    internal record struct Struct5
+    {
+        public Struct5(int value)
+        {
+            Int1 = Int2 = Int3 = Int4 = Int5 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+        public int Int3;
+        public int Int4;
+        public int Int5;
+    }
+
+    internal record struct Struct6
+    {
+        public Struct6(int value)
+        {
+            Int1 = Int2 = Int3 = Int4 = Int5 = Int6 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+        public int Int3;
+        public int Int4;
+        public int Int5;
+        public int Int6;
+    }
+
+    internal record struct Struct7
+    {
+        public Struct7(int value)
+        {
+            Int1 = Int2 = Int3 = Int4 = Int5 = Int6 = Int7 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+        public int Int3;
+        public int Int4;
+        public int Int5;
+        public int Int6;
+        public int Int7;
+    }
+
+    internal record struct Struct8
+    {
+        public Struct8(int value)
+        {
+            Int1 = Int2 = Int3 = Int4 = Int5 = Int6 = Int7 = Int8 = value;
+        }
+
+        public int Int1;
+        public int Int2;
+        public int Int3;
+        public int Int4;
+        public int Int5;
+        public int Int6;
+        public int Int7;
+        public int Int8;
+    }
+}