Add benchmarks

This commit is contained in:
Asriel Camora
2023-06-21 20:44:13 -07:00
parent dba76e319c
commit 0de1faa112
4 changed files with 97 additions and 12 deletions
+59
View File
@@ -0,0 +1,59 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace Craftimizer.Benchmark;
[SimpleJob(RuntimeMoniker.Net70)]
[SimpleJob(RuntimeMoniker.NativeAot70)]
public class Bench
{
private float[] data;
private int[] dataLengths;
[Params(1000, 10000)]
public int N;
[GlobalSetup]
public void Setup()
{
var rand = new Random();
data = new float[N * 8];
dataLengths = new int[N];
for (var i = 0; i < data.Length; i += 8)
{
var len = rand.NextSingle() > .5 ? 8 : rand.Next(1, 9);
dataLengths[i / 8] = len;
for (var j = 0; j < len; ++j)
data[i + j] = rand.NextSingle();
for (var j = len; j < 8; ++j)
data[i + j] = float.NaN;
}
}
[Benchmark]
public int[] Scalar()
{
var d = new int[N];
var dataSpan = data.AsSpan();
for (var i = 0; i < N; ++i)
d[i] = Solver.Crafty.Solver.HMaxIndexScalar(new Vector<float>(dataSpan.Slice(i * 8, 8)), dataLengths[i]);
return d;
}
[Benchmark]
public int[] AVX2()
{
var d = new int[128];
var dataSpan = data.AsSpan();
for (var i = 0; i < 128; ++i)
d[i] = Solver.Crafty.Solver.HMaxIndexAVX2(new Vector<float>(dataSpan.Slice(i * 8, 8)), dataLengths[i]);
return d;
}
}
+1
View File
@@ -8,6 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.61"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.61">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+5 -1
View File
@@ -1,3 +1,4 @@
using BenchmarkDotNet.Running;
using Craftimizer.Simulator; using Craftimizer.Simulator;
using Craftimizer.Simulator.Actions; using Craftimizer.Simulator.Actions;
using Craftimizer.Solver.Crafty; using Craftimizer.Solver.Crafty;
@@ -10,6 +11,9 @@ internal static class Program
{ {
private static void Main() private static void Main()
{ {
//var summary = BenchmarkRunner.Run<Bench>();
//return;
//TypeLayout.PrintLayout<ArenaNode<SimulationNode>>(true); //TypeLayout.PrintLayout<ArenaNode<SimulationNode>>(true);
//return; //return;
@@ -33,7 +37,7 @@ internal static class Program
var config = new SolverConfig() var config = new SolverConfig()
{ {
Iterations = 1_000_000 Iterations = 30_000,//1_000_000
}; };
var s = Stopwatch.StartNew(); var s = Stopwatch.StartNew();
+32 -11
View File
@@ -99,23 +99,45 @@ public class Solver
[Pure] [Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
// https://stackoverflow.com/a/23592221 public static int HMaxIndexScalar(Vector<float> v, int len)
private static (int, uint) HMaxIndex(Vector256<float> v, int len)
{ {
var vfilt = Avx.Blend(v, Vector256<float>.Zero, (byte)~((1 << len) - 1)); var m = 0;
for (var i = 1; i < len; ++i)
{
if (v[i] >= v[m])
m = i;
}
return m;
}
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// https://stackoverflow.com/a/23592221
public static int HMaxIndexAVX2(Vector<float> v, int len)
{
// Remove NaNs
var vfilt = Avx.Blend(v.AsVector256(), Vector256<float>.Zero, (byte)~((1 << len) - 1));
// Find max value and broadcast to all lanes
var vmax128 = HMax(vfilt); var vmax128 = HMax(vfilt);
var vmax = Vector256.Create(vmax128, vmax128); var vmax = Vector256.Create(vmax128, vmax128);
var vcmp = Avx.CompareEqual(v, vmax); // Find the highest index with that value, respecting len
var vcmp = Avx.CompareEqual(vfilt, vmax);
var mask = unchecked((uint)Avx2.MoveMask(vcmp.AsByte())); var mask = unchecked((uint)Avx2.MoveMask(vcmp.AsByte()));
mask <<= (8 - len) << 2;
var inverseIdx = BitOperations.LeadingZeroCount(mask) >> 2; var inverseIdx = BitOperations.LeadingZeroCount(mask << ((8 - len) << 2)) >> 2;
return (len - 1 - inverseIdx, mask); return len - 1 - inverseIdx;
} }
[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int HMaxIndex(Vector<float> v, int len) =>
Avx2.IsSupported ?
HMaxIndexAVX2(v, len) :
HMaxIndexScalar(v, len);
[Pure] [Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Node EvalBestChild(float parentVisits, ReadOnlySpan<Node> children) private Node EvalBestChild(float parentVisits, ReadOnlySpan<Node> children)
@@ -134,7 +156,6 @@ public class Solver
var max = 0; var max = 0;
var maxScore = 0f; var maxScore = 0f;
for (var i = 0; i < length; i += vecLength) for (var i = 0; i < length; i += vecLength)
{ {
var iterCount = i + vecLength > length ? var iterCount = i + vecLength > length ?
@@ -153,7 +174,7 @@ public class Solver
var exploration = Vector.SquareRoot(CVector / new Vector<float>(visits)); var exploration = Vector.SquareRoot(CVector / new Vector<float>(visits));
var evalScores = exploitation + exploration; var evalScores = exploitation + exploration;
var (idx, mask) = HMaxIndex(evalScores.AsVector256(), iterCount); var idx = HMaxIndex(evalScores, iterCount);
if (evalScores[idx] >= maxScore) if (evalScores[idx] >= maxScore)
{ {
@@ -186,7 +207,7 @@ public class Solver
if (initialState.IsComplete) if (initialState.IsComplete)
return (initialNode, initialState.CompletionState, initialState.CalculateScore(Config.MaxStepCount) ?? 0); return (initialNode, initialState.CompletionState, initialState.CalculateScore(Config.MaxStepCount) ?? 0);
var randomAction = initialState.AvailableActions.SelectRandom(Random); var randomAction = initialState.AvailableActions.First();//.SelectRandom(Random);
initialState.AvailableActions.RemoveAction(randomAction); initialState.AvailableActions.RemoveAction(randomAction);
var expandedNode = initialNode.Add(Execute(initialState.State, randomAction, true)); var expandedNode = initialNode.Add(Execute(initialState.State, randomAction, true));
@@ -201,7 +222,7 @@ public class Solver
{ {
if (SimulationNode.GetCompletionState(currentCompletionState, currentActions) != CompletionState.Incomplete) if (SimulationNode.GetCompletionState(currentCompletionState, currentActions) != CompletionState.Incomplete)
break; break;
randomAction = currentActions.SelectRandom(Random); randomAction = currentActions.First();//.SelectRandom(Random);
actions[actionCount++] = randomAction; actions[actionCount++] = randomAction;
(_, currentState) = Simulator.Execute(currentState, randomAction); (_, currentState) = Simulator.Execute(currentState, randomAction);
currentCompletionState = Simulator.CompletionState; currentCompletionState = Simulator.CompletionState;