AyCode.Core/AyCode.Benchmark/RefForeachBenchmark.cs

158 lines
3.9 KiB
C#

using BenchmarkDotNet.Attributes;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.VSDiagnostics;
namespace AyCode.Benchmark;
[CPUUsageDiagnoser]
public class RefForeachBenchmark
{
// Simulates BinaryPropertyAccessor (large struct ~80 bytes)
public struct PropertyAccessor
{
public int PropertyIndex;
public TypeCode PropertyTypeCode;
public int AccessorType;
public long Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly int GetValue() => PropertyIndex + (int)PropertyTypeCode + AccessorType;
}
private PropertyAccessor[] _properties = null !;
private List<PropertyAccessor> _propertiesList = null !;
[GlobalSetup]
public void Setup()
{
_properties = new PropertyAccessor[20]; // Typical property count
_propertiesList = new List<PropertyAccessor>(20);
for (int i = 0; i < 20; i++)
{
var prop = new PropertyAccessor
{
PropertyIndex = i,
PropertyTypeCode = TypeCode.Int32,
AccessorType = i % 5,
Field1 = i,
Field2 = i,
Field3 = i,
Field4 = i,
Field5 = i,
Field6 = i,
Field7 = i,
Field8 = i
};
_properties[i] = prop;
_propertiesList.Add(prop);
}
}
// ============ ARRAY ITERATION ============
[Benchmark(Baseline = true)]
public int Array_ForEach_ByValue()
{
int total = 0;
for (int iter = 0; iter < 1000; iter++)
{
foreach (var prop in _properties)
{
total += prop.GetValue();
}
}
return total;
}
[Benchmark]
public int Array_ForEach_RefReadonly()
{
int total = 0;
for (int iter = 0; iter < 1000; iter++)
{
foreach (ref readonly var prop in _properties.AsSpan())
{
total += prop.GetValue();
}
}
return total;
}
[Benchmark]
public int Array_ForLoop_Index()
{
int total = 0;
var props = _properties;
for (int iter = 0; iter < 1000; iter++)
{
for (int i = 0; i < props.Length; i++)
{
total += props[i].GetValue();
}
}
return total;
}
[Benchmark]
public int Array_ForLoop_Span()
{
int total = 0;
for (int iter = 0; iter < 1000; iter++)
{
var span = _properties.AsSpan();
for (int i = 0; i < span.Length; i++)
{
total += span[i].GetValue();
}
}
return total;
}
// ============ LIST ITERATION ============
[Benchmark]
public int List_ForEach_ByValue()
{
int total = 0;
for (int iter = 0; iter < 1000; iter++)
{
foreach (var prop in _propertiesList)
{
total += prop.GetValue();
}
}
return total;
}
[Benchmark]
public int List_CollectionsMarshal_RefReadonly()
{
int total = 0;
for (int iter = 0; iter < 1000; iter++)
{
foreach (ref readonly var prop in CollectionsMarshal.AsSpan(_propertiesList))
{
total += prop.GetValue();
}
}
return total;
}
[Benchmark]
public int List_ForLoop_Index()
{
int total = 0;
var props = _propertiesList;
for (int iter = 0; iter < 1000; iter++)
{
for (int i = 0; i < props.Count; i++)
{
total += props[i].GetValue();
}
}
return total;
}
}