158 lines
3.9 KiB
C#
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;
|
|
}
|
|
} |