Some multithreaded fixes, deadlocks due to List reads during adds
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.61">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.62">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -45,10 +45,11 @@ internal static class Program
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var threads = 1;
|
||||||
var config = new SolverConfig()
|
var config = new SolverConfig()
|
||||||
{
|
{
|
||||||
Iterations = 30_000 / 1,
|
Iterations = 30_000 / threads,
|
||||||
ThreadCount = 1,
|
ThreadCount = threads,
|
||||||
};
|
};
|
||||||
|
|
||||||
Debugger.Break();
|
Debugger.Break();
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.11" />
|
<PackageReference Include="DalamudPackager" Version="2.1.11" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.61">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.62">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -10,9 +10,9 @@
|
|||||||
},
|
},
|
||||||
"Meziantou.Analyzer": {
|
"Meziantou.Analyzer": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[2.0.61, )",
|
"requested": "[2.0.62, )",
|
||||||
"resolved": "2.0.61",
|
"resolved": "2.0.62",
|
||||||
"contentHash": "DhiEScqTxQb8R7s9EWMjs5F5EA7AD+JO5upb88QqPwPQUsAOm2gN5AjeQon3XLrquw1G5r+C9Yxct+rFxwuMZg=="
|
"contentHash": "uG2CiDIm97q8KrUt8B34WdElpEDDLOe4YzrLWpwlQmesXrSX2WuJZ+HwIGWrJgDBBMi2a3tVjeF8oKjV+AhUdA=="
|
||||||
},
|
},
|
||||||
"craftimizer.simulator": {
|
"craftimizer.simulator": {
|
||||||
"type": "Project"
|
"type": "Project"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.61">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.62">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.61">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.62">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Craftimizer.Simulator.Actions;
|
using Craftimizer.Simulator.Actions;
|
||||||
|
using System;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -54,6 +55,54 @@ public struct ActionSet
|
|||||||
//public readonly ActionType SelectRandom(Random random) => ElementAt(random.Next(Count));
|
//public readonly ActionType SelectRandom(Random random) => ElementAt(random.Next(Count));
|
||||||
public readonly ActionType SelectRandom(Random random) => First();
|
public readonly ActionType SelectRandom(Random random) => First();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ActionType? PopRandom(Random random) => PopFirst();
|
||||||
|
/*public ActionType? PopRandom(Random random)
|
||||||
|
{
|
||||||
|
uint snapshot;
|
||||||
|
uint newValue;
|
||||||
|
ActionType action;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
snapshot = bits;
|
||||||
|
if (snapshot == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var count = BitOperations.PopCount(snapshot);
|
||||||
|
var index = random.Next(count);
|
||||||
|
|
||||||
|
action = ToAction(Intrinsics.NthBitSet(snapshot, index) - 1);
|
||||||
|
newValue = snapshot & ~ToMask(action);
|
||||||
|
}
|
||||||
|
while (Interlocked.CompareExchange(ref bits, newValue, snapshot) != snapshot);
|
||||||
|
return action;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public ActionType? PopFirst()
|
||||||
|
{
|
||||||
|
uint snapshot;
|
||||||
|
uint newValue;
|
||||||
|
ActionType action;
|
||||||
|
int i = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
snapshot = bits;
|
||||||
|
if (snapshot == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
|
||||||
|
action = ToAction(Intrinsics.NthBitSet(snapshot, index) - 1);
|
||||||
|
newValue = snapshot & ~ToMask(action);
|
||||||
|
}
|
||||||
|
while (Interlocked.CompareExchange(ref bits, newValue, snapshot) != snapshot);
|
||||||
|
//if (i != 1)
|
||||||
|
//Console.WriteLine($"Retried {i-1} times");
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
[Pure]
|
[Pure]
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly ActionType First() => ElementAt(0);
|
public readonly ActionType First() => ElementAt(0);
|
||||||
|
|||||||
+31
-20
@@ -19,7 +19,7 @@ public class Solver
|
|||||||
public Solver(SolverConfig config, SimulationState state, bool strict)
|
public Solver(SolverConfig config, SimulationState state, bool strict)
|
||||||
{
|
{
|
||||||
Config = config;
|
Config = config;
|
||||||
Simulator sim = new(state, config.MaxStepCount);
|
var sim = new Simulator(state, config.MaxStepCount);
|
||||||
RootNode = new(new(
|
RootNode = new(new(
|
||||||
state,
|
state,
|
||||||
null,
|
null,
|
||||||
@@ -98,7 +98,12 @@ public class Solver
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private Node EvalBestChild(float parentVisits, ReadOnlySpan<Node> children)
|
private Node EvalBestChild(float parentVisits, ReadOnlySpan<Node> children)
|
||||||
{
|
{
|
||||||
var length = children.Length;
|
if (parentVisits == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("no visits");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var vecLength = Vector<float>.Count;
|
var vecLength = Vector<float>.Count;
|
||||||
|
|
||||||
var C = MathF.Sqrt(Config.ExplorationConstant * MathF.Log(parentVisits));
|
var C = MathF.Sqrt(Config.ExplorationConstant * MathF.Log(parentVisits));
|
||||||
@@ -152,30 +157,28 @@ public class Solver
|
|||||||
var node = RootNode;
|
var node = RootNode;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!Monitor.TryEnter(node, 5))
|
var expandable = !node.State.AvailableActions.IsEmpty;
|
||||||
return Select();
|
|
||||||
var expandable = node.State.AvailableActions.Count != 0;
|
|
||||||
var likelyTerminal = node.Children.Count == 0;
|
var likelyTerminal = node.Children.Count == 0;
|
||||||
if (expandable || likelyTerminal)
|
if (expandable || likelyTerminal)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
// select the node with the highest score
|
// select the node with the highest score
|
||||||
var n = EvalBestChild(node.State.Scores.Visits, CollectionsMarshal.AsSpan(node.Children));
|
// if null (current node is invalid & not backpropagated just yet), try again from root
|
||||||
Monitor.Exit(node);
|
node = EvalBestChild(node.State.Scores.Visits, node.Children) ?? RootNode;
|
||||||
node = n;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Node ExpandedNode, CompletionState State, float Score) ExpandAndRollout(Simulator simulator, Node initialNode)
|
public (Node ExpandedNode, float Score)? ExpandAndRollout(Simulator simulator, Node initialNode)
|
||||||
{
|
{
|
||||||
ref var initialState = ref initialNode.State;
|
ref var initialState = ref initialNode.State;
|
||||||
// expand once
|
// expand once
|
||||||
if (initialState.IsComplete)
|
if (initialState.IsComplete)
|
||||||
return (initialNode, initialState.CompletionState, initialState.CalculateScore(Config.MaxStepCount) ?? 0);
|
return (initialNode, initialState.CalculateScore(Config.MaxStepCount) ?? 0);
|
||||||
|
|
||||||
var randomAction = initialState.AvailableActions.SelectRandom(Random);
|
var poppedAction = initialState.AvailableActions.PopRandom(Random);
|
||||||
initialState.AvailableActions.RemoveAction(randomAction);
|
if (!poppedAction.HasValue)
|
||||||
var expandedNode = initialNode.Add(Execute(simulator, initialState.State, randomAction, true));
|
return null;
|
||||||
|
var expandedNode = initialNode.Add(Execute(simulator, initialState.State, poppedAction.Value, true));
|
||||||
|
|
||||||
// playout to a terminal state
|
// playout to a terminal state
|
||||||
var currentState = expandedNode.State.State;
|
var currentState = expandedNode.State.State;
|
||||||
@@ -188,9 +191,9 @@ public class Solver
|
|||||||
{
|
{
|
||||||
if (SimulationNode.GetCompletionState(currentCompletionState, currentActions) != CompletionState.Incomplete)
|
if (SimulationNode.GetCompletionState(currentCompletionState, currentActions) != CompletionState.Incomplete)
|
||||||
break;
|
break;
|
||||||
randomAction = currentActions.SelectRandom(Random);
|
var nextAction = currentActions.SelectRandom(Random);
|
||||||
actions[actionCount++] = randomAction;
|
actions[actionCount++] = nextAction;
|
||||||
(_, currentState) = simulator.Execute(currentState, randomAction);
|
(_, currentState) = simulator.Execute(currentState, nextAction);
|
||||||
currentCompletionState = simulator.CompletionState;
|
currentCompletionState = simulator.CompletionState;
|
||||||
currentActions = simulator.AvailableActionsHeuristic(true);
|
currentActions = simulator.AvailableActionsHeuristic(true);
|
||||||
}
|
}
|
||||||
@@ -202,10 +205,10 @@ public class Solver
|
|||||||
if (score >= Config.ScoreStorageThreshold && score >= RootNode.State.Scores.MaxScore)
|
if (score >= Config.ScoreStorageThreshold && score >= RootNode.State.Scores.MaxScore)
|
||||||
{
|
{
|
||||||
(var terminalNode, _) = ExecuteActions(simulator, expandedNode, actions[..actionCount], true);
|
(var terminalNode, _) = ExecuteActions(simulator, expandedNode, actions[..actionCount], true);
|
||||||
return (terminalNode, currentCompletionState, score);
|
return (terminalNode, score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (expandedNode, currentCompletionState, score);
|
return (expandedNode, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Backpropagate(Node startNode, float score)
|
public void Backpropagate(Node startNode, float score)
|
||||||
@@ -230,9 +233,17 @@ public class Solver
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
var selectedNode = Select();
|
var selectedNode = Select();
|
||||||
var (endNode, _, score) = ExpandAndRollout(simulator, selectedNode);
|
var rolledOut = ExpandAndRollout(simulator, selectedNode);
|
||||||
Monitor.Exit(selectedNode);
|
//Monitor.Exit(selectedNode);
|
||||||
|
if (!rolledOut.HasValue)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Retry");
|
||||||
|
// Retry, count this iteration as moot
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (endNode, score) = rolledOut.Value;
|
||||||
Backpropagate(endNode, score);
|
Backpropagate(endNode, score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user