diff --git a/Simulator/Actions/ActionType.cs b/Simulator/Actions/ActionType.cs index 1c6e589..d3c3407 100644 --- a/Simulator/Actions/ActionType.cs +++ b/Simulator/Actions/ActionType.cs @@ -47,7 +47,7 @@ public enum ActionType : byte public static class ActionUtils { - private static readonly BaseAction[] Actions; + private static ReadOnlyMemory Actions { get; } static ActionUtils() { @@ -61,7 +61,7 @@ static ActionUtils() [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static BaseAction Base(this ActionType me) => Actions[(int)me]; + public static BaseAction Base(this ActionType me) => Actions.Span[(int)me]; public static IEnumerable AvailableActions(Simulator simulation) => simulation.IsComplete diff --git a/Simulator/SimulationState.cs b/Simulator/SimulationState.cs index 74cac04..8147cdb 100644 --- a/Simulator/SimulationState.cs +++ b/Simulator/SimulationState.cs @@ -18,7 +18,7 @@ public record struct SimulationState public ActionStates ActionStates; // https://github.com/ffxiv-teamcraft/simulator/blob/0682dfa76043ff4ccb38832c184d046ceaff0733/src/model/tables.ts#L2 - private static readonly int[] HQPercentTable = { + private static ReadOnlySpan HQPercentTable => new[] { 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 20, 20, 21, 22, 23, 24, 26, 28, 31, 34, 38, 42, 47, 52, 58, 64, 68, 71, @@ -44,13 +44,4 @@ public SimulationState(SimulationInput input) ActionCount = 0; ActionStates = new(); } - -#if IS_DETERMINISTIC - public override readonly string ToString() - { - var b = new System.Text.StringBuilder(); - PrintMembers(b); - return Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(System.Text.Encoding.UTF8.GetBytes(b.ToString()))); - } -#endif } diff --git a/Solver/MCTS.cs b/Solver/MCTS.cs index 76251db..c340018 100644 --- a/Solver/MCTS.cs +++ b/Solver/MCTS.cs @@ -72,8 +72,8 @@ private static (int arrayIdx, int subIdx) ChildMaxScore(in NodeScoresBuffer scor { var iterCount = Math.Min(vecLength, length); - ref var chunk = ref scores.Data[i]; - var m = new Vector(chunk.MaxScore.Span); + ref var chunk = ref scores.Data!.Value.Span[i]; + var m = new Vector(chunk.MaxScore); var idx = Intrinsics.HMaxIndex(m, iterCount); @@ -127,10 +127,10 @@ private static (int arrayIdx, int subIdx) EvalBestChild( { var iterCount = Math.Min(vecLength, length); - ref var chunk = ref scores.Data[i]; - var s = new Vector(chunk.ScoreSum.Span); - var vInt = new Vector(chunk.Visits.Span); - var m = new Vector(chunk.MaxScore.Span); + ref var chunk = ref scores.Data!.Value.Span[i]; + var s = new Vector(chunk.ScoreSum); + var vInt = new Vector(chunk.Visits); + var m = new Vector(chunk.MaxScore); vInt = Vector.Max(vInt, Vector.One); var v = Vector.ConvertToSingle(vInt); diff --git a/Solver/NodeScoresBuffer.cs b/Solver/NodeScoresBuffer.cs index fecfb40..36c3077 100644 --- a/Solver/NodeScoresBuffer.cs +++ b/Solver/NodeScoresBuffer.cs @@ -1,24 +1,26 @@ using System.Diagnostics.Contracts; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Craftimizer.Solver; // Adapted from https://github.com/dtao/ConcurrentList/blob/4fcf1c76e93021a41af5abb2d61a63caeba2adad/ConcurrentList/ConcurrentList.cs public struct NodeScoresBuffer { - public sealed class ScoresBatch + public readonly struct ScoresBatch { - public Memory ScoreSum; - public Memory MaxScore; - public Memory Visits; - - public ScoresBatch() - { - ScoreSum = new float[BatchSize]; - MaxScore = new float[BatchSize]; - Visits = new int[BatchSize]; - } + private readonly Memory data; + + public Span ScoreSum => + MemoryMarshal.Cast(data.Span.Slice(0, BatchSize * sizeof(float))); + public Span MaxScore => + MemoryMarshal.Cast(data.Span.Slice(BatchSize * sizeof(float), BatchSize * sizeof(float))); + public Span Visits => + MemoryMarshal.Cast(data.Span.Slice(BatchSize * sizeof(float) * 2, BatchSize * sizeof(int))); + + public ScoresBatch() => + data = new byte[BatchSize * sizeof(float) * 3]; } // Technically 25, but it's very unlikely to actually get to there. @@ -31,7 +33,7 @@ public ScoresBatch() private static readonly int BatchCount = MaxSize / BatchSize; - public ScoresBatch[] Data; + public Memory? Data; public int Count { get; private set; } public void Add() @@ -40,20 +42,22 @@ public void Add() var idx = Count++; - var (arrayIdx, _) = GetArrayIndex(idx); + var (arrayIdx, subIdx) = GetArrayIndex(idx); - Data[arrayIdx] ??= new(); + if (subIdx == 0) + Data.Value.Span[arrayIdx] = new(); } public readonly void Visit((int arrayIdx, int subIdx) at, float score) { - Data[at.arrayIdx].ScoreSum.Span[at.subIdx] += score; - Data[at.arrayIdx].MaxScore.Span[at.subIdx] = Math.Max(Data[at.arrayIdx].MaxScore.Span[at.subIdx], score); - Data[at.arrayIdx].Visits.Span[at.subIdx]++; + ref var batch = ref Data!.Value.Span[at.arrayIdx]; + batch.ScoreSum[at.subIdx] += score; + batch.MaxScore[at.subIdx] = Math.Max(batch.MaxScore[at.subIdx], score); + batch.Visits[at.subIdx]++; } public readonly int GetVisits((int arrayIdx, int subIdx) at) => - Data[at.arrayIdx].Visits.Span[at.subIdx]; + Data!.Value.Span[at.arrayIdx].Visits[at.subIdx]; [Pure] [MethodImpl(MethodImplOptions.AggressiveInlining)]