chore: hexpats + MemCasting benchmarks
This commit is contained in:
parent
863332b806
commit
09f8dda990
2 changed files with 178 additions and 0 deletions
178
Benchmarks/MemCasting.cs
Normal file
178
Benchmarks/MemCasting.cs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||||
|
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Order;
|
||||||
|
|
||||||
|
namespace Benchmarks;
|
||||||
|
|
||||||
|
[Config(typeof(GenericConfig))]
|
||||||
|
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||||
|
public class MemCasting
|
||||||
|
{
|
||||||
|
private byte[] _data = null!;
|
||||||
|
private byte[] _arrayData = null!;
|
||||||
|
|
||||||
|
[Params(1000, 100000, 1000000)] public int N;
|
||||||
|
[GlobalSetup]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_data = new byte[64];
|
||||||
|
_arrayData = new byte[N * 64];
|
||||||
|
Random.Shared.NextBytes(_data);
|
||||||
|
Random.Shared.NextBytes(_arrayData);
|
||||||
|
}
|
||||||
|
private static ElementalStats ReadElementalStatsMemoryMarshal(ref Span<byte> data)
|
||||||
|
{
|
||||||
|
return MemoryMarshal.Cast<byte, ElementalStats>(data.Slice(0, 64))[0];
|
||||||
|
}
|
||||||
|
private static ElementalStats ReadElementalStatsMemoryMarshal2(ref Span<byte> data)
|
||||||
|
{
|
||||||
|
return MemoryMarshal.Read<ElementalStats>(data.Slice(0, 64));
|
||||||
|
}
|
||||||
|
private static ElementalStats ReadElementalStatsNew(ref Span<byte> data)
|
||||||
|
{
|
||||||
|
return new ElementalStats
|
||||||
|
{
|
||||||
|
MinimumFireDamage = BitConverter.ToInt32(data.Slice(0, 4)), // 140 -> 144
|
||||||
|
MinimumWaterDamage = BitConverter.ToInt32(data.Slice(4, 4)), // 144 -> 148
|
||||||
|
MinimumDarkDamage = BitConverter.ToInt32(data.Slice(8, 4)), // 148 -> 152
|
||||||
|
MinimumHolyDamage = BitConverter.ToInt32(data.Slice(12, 4)), // 152 -> 156
|
||||||
|
MaximumFireDamage = BitConverter.ToInt32(data.Slice(16, 4)), // 156 -> 160
|
||||||
|
MaximumWaterDamage = BitConverter.ToInt32(data.Slice(20, 4)), // 160 -> 164
|
||||||
|
MaximumDarkDamage = BitConverter.ToInt32(data.Slice(24, 4)), // 164 -> 168
|
||||||
|
MaximumHolyDamage = BitConverter.ToInt32(data.Slice(28, 4)), // 168 -> 172
|
||||||
|
ElementFire = BitConverter.ToUInt32(data.Slice(32, 4)), // 172 -> 176
|
||||||
|
ElementWater = BitConverter.ToUInt32(data.Slice(36, 4)), // 176 -> 180
|
||||||
|
ElementDark = BitConverter.ToUInt32(data.Slice(40, 4)), // 180 -> 184
|
||||||
|
ElementHoly = BitConverter.ToUInt32(data.Slice(44, 4)), // 184 -> 188
|
||||||
|
FireResistance = BitConverter.ToInt32(data.Slice(48, 4)), // 188 -> 192
|
||||||
|
WaterResistance = BitConverter.ToInt32(data.Slice(52, 4)), // 192 -> 196
|
||||||
|
DarkResistance = BitConverter.ToInt32(data.Slice(56, 4)), // 196 -> 200
|
||||||
|
HolyResistance = BitConverter.ToInt32(data.Slice(60, 4)) // 200 -> 204
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Span<ElementalStats> MemoryMarshalCastArray()
|
||||||
|
{
|
||||||
|
var data = _arrayData.AsSpan();
|
||||||
|
var elements = MemoryMarshal.Cast<byte, ElementalStats>(data);
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public Span<ElementalStats> MemoryMarshalReadArray()
|
||||||
|
{
|
||||||
|
Span<ElementalStats> statsArr = stackalloc ElementalStats[N + 1];
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
for (int i = 0; i <= N; i++)
|
||||||
|
{
|
||||||
|
statsArr[i] = ReadElementalStatsMemoryMarshal2(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statsArr.ToArray();
|
||||||
|
}
|
||||||
|
[Benchmark]
|
||||||
|
public Span<ElementalStats> ManualSpanSlicingArray()
|
||||||
|
{
|
||||||
|
Span<ElementalStats> statsArr = stackalloc ElementalStats[N + 1];
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
for (int i = 0; i <= N; i++)
|
||||||
|
{
|
||||||
|
statsArr[i] = ReadElementalStatsNew(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statsArr.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ElementalStats MemoryMarshalCastSingle()
|
||||||
|
{
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
return ReadElementalStatsMemoryMarshal(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public ElementalStats MemoryMarshalReadSingle()
|
||||||
|
{
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
return ReadElementalStatsMemoryMarshal2(ref data);
|
||||||
|
}
|
||||||
|
[Benchmark]
|
||||||
|
public ElementalStats ManualSpanSlicingSingle()
|
||||||
|
{
|
||||||
|
var data = _data.AsSpan();
|
||||||
|
return ReadElementalStatsNew(ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
||||||
|
public struct ElementalStats
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumFireDamage;
|
||||||
|
|
||||||
|
[FieldOffset(4)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumWaterDamage;
|
||||||
|
|
||||||
|
[FieldOffset(8)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumDarkDamage;
|
||||||
|
|
||||||
|
[FieldOffset(12)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MinimumHolyDamage;
|
||||||
|
|
||||||
|
[FieldOffset(16)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumFireDamage;
|
||||||
|
|
||||||
|
[FieldOffset(20)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumWaterDamage;
|
||||||
|
|
||||||
|
[FieldOffset(24)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumDarkDamage;
|
||||||
|
|
||||||
|
[FieldOffset(28)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int MaximumHolyDamage;
|
||||||
|
|
||||||
|
[FieldOffset(32)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementFire;
|
||||||
|
|
||||||
|
[FieldOffset(36)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementWater;
|
||||||
|
|
||||||
|
[FieldOffset(40)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementDark;
|
||||||
|
|
||||||
|
[FieldOffset(44)]
|
||||||
|
[MarshalAs(UnmanagedType.U4)]
|
||||||
|
public uint ElementHoly;
|
||||||
|
|
||||||
|
[FieldOffset(48)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int FireResistance;
|
||||||
|
|
||||||
|
[FieldOffset(52)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int WaterResistance;
|
||||||
|
|
||||||
|
[FieldOffset(56)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int DarkResistance;
|
||||||
|
|
||||||
|
[FieldOffset(60)]
|
||||||
|
[MarshalAs(UnmanagedType.I4)]
|
||||||
|
public int HolyResistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
Loading…
Reference in a new issue