Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🧹 Move TT outside of Engine: class wrapper #1184

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d86b32f
Move time management calculations and UCI best move printing from Eng…
eduherminio Nov 4, 2024
240179d
Add missing `in`
eduherminio Nov 4, 2024
73541f6
Move TT outside of Engine, and wrap the actual array in a class insta…
eduherminio Nov 4, 2024
73c5abe
_ttWraper -> _tt
eduherminio Nov 4, 2024
684f00f
Renames
eduherminio Nov 4, 2024
2add9fb
Move Lynx init logic to Runner
eduherminio Nov 9, 2024
8653b29
Allow the searcher to initialize the engine
eduherminio Nov 9, 2024
55e0eee
Merge branch 'main' into refactor/tm-outside-of-engine
eduherminio Nov 11, 2024
1730109
Merge branch 'refactor/tm-outside-of-engine' into refactor/tt-outside…
eduherminio Nov 11, 2024
684800a
Move `PrefetchTTEntry()` from Helpers to TranspositionTable
eduherminio Nov 11, 2024
0d5bc81
Merge remote-tracking branch 'origin/main' into refactor/tt-outside-o…
eduherminio Nov 19, 2024
9ba9b5b
Fix merge
eduherminio Nov 19, 2024
b92611e
Revert unnecessary changes
eduherminio Nov 19, 2024
6820077
Avoid name conflict in Program dev
eduherminio Nov 19, 2024
5113da9
Merge branch 'main' into refactor/tm-outside-of-engine
eduherminio Nov 19, 2024
21b3cbc
Merge branch 'refactor/tm-outside-of-engine' into refactor/tt-outside…
eduherminio Nov 19, 2024
b46009d
Merge with main
eduherminio Nov 21, 2024
883440f
Pass Searcher instead of Engine to UCIHandler, and don't expose Engin…
eduherminio Nov 21, 2024
f45f121
Merge with main
eduherminio Nov 22, 2024
b967970
Merge remote-tracking branch 'origin/main' into refactor/tt-outside-o…
eduherminio Nov 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 1 addition & 51 deletions src/Lynx.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using Lynx;
using Lynx.Cli;
using Lynx.UCI.Commands.Engine;
using Microsoft.Extensions.Configuration;
using NLog;
using NLog.Extensions.Logging;
using System.Threading.Channels;

#if DEBUG
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
Expand All @@ -26,54 +24,6 @@
LogManager.Configuration = new NLogLoggingConfiguration(config.GetSection("NLog"));
}

var uciChannel = Channel.CreateBounded<string>(new BoundedChannelOptions(100) { SingleReader = true, SingleWriter = true, FullMode = BoundedChannelFullMode.Wait });
var engineChannel = Channel.CreateBounded<object>(new BoundedChannelOptions(2 * Configuration.EngineSettings.MaxDepth) { SingleReader = true, SingleWriter = false, FullMode = BoundedChannelFullMode.DropOldest });

using CancellationTokenSource source = new();
CancellationToken cancellationToken = source.Token;

var engine = new Engine(engineChannel);
var uciHandler = new UCIHandler(uciChannel, engineChannel, engine);

var tasks = new List<Task>
{
Task.Run(() => new Writer(engineChannel).Run(cancellationToken)),
Task.Run(() => new Searcher(uciChannel, engineChannel, engine).Run(cancellationToken)),
Task.Run(() => new Listener(uciHandler).Run(cancellationToken, args)),
uciChannel.Reader.Completion,
engineChannel.Reader.Completion
};

try
{
Console.WriteLine($"{IdCommand.EngineName} {IdCommand.GetVersion()} by {IdCommand.EngineAuthor}");
await Task.WhenAny(tasks);
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
if (e is TaskCanceledException taskCanceledException)
{
Console.WriteLine("Cancellation requested: {0}", taskCanceledException.Message);
}
else
{
Console.WriteLine("Exception: {0}", e.GetType().Name);
}
}
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception");
Console.WriteLine(e.Message);
}
finally
{
engineChannel.Writer.TryComplete();
uciChannel.Writer.TryComplete();
//source.Cancel();
LogManager.Shutdown(); // Flush and close down internal threads and timers
}
await Runner.Run(args);

Thread.Sleep(2_000);
69 changes: 69 additions & 0 deletions src/Lynx.Cli/Runner.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Lynx.UCI.Commands.Engine;
using NLog;
using System.Threading.Channels;

namespace Lynx.Cli;

public static class Runner
{
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();

public static async Task Run(params string[] args)
{
var uciChannel = Channel.CreateBounded<string>(new BoundedChannelOptions(100) { SingleReader = true, SingleWriter = true, FullMode = BoundedChannelFullMode.Wait });
var engineChannel = Channel.CreateBounded<object>(new BoundedChannelOptions(2 * Configuration.EngineSettings.MaxDepth) { SingleReader = true, SingleWriter = false, FullMode = BoundedChannelFullMode.DropOldest });

using CancellationTokenSource source = new();
CancellationToken cancellationToken = source.Token;

var searcher = new Searcher(uciChannel, engineChannel);
var uciHandler = new UCIHandler(uciChannel, engineChannel, searcher);
var writer = new Writer(engineChannel);
var listener = new Listener(uciHandler);

var tasks = new List<Task>
{
Task.Run(() => writer.Run(cancellationToken)),
Task.Run(() => searcher.Run(cancellationToken)),
Task.Run(() => listener.Run(cancellationToken, args)),
uciChannel.Reader.Completion,
engineChannel.Reader.Completion
};

try
{
Console.WriteLine($"{IdCommand.EngineName} {IdCommand.GetVersion()} by {IdCommand.EngineAuthor}");
await Task.WhenAny(tasks);
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
if (e is TaskCanceledException taskCanceledException)
{
Console.WriteLine("Cancellation requested exception: {0}", taskCanceledException.Message);
_logger.Fatal(ae, "Cancellation requested exception: {0}", taskCanceledException.Message);
}
else
{
Console.WriteLine("Exception {0}: {1}", e.GetType().Name, e.Message);
_logger.Fatal(ae, "Exception {0}: {1}", e.GetType().Name, e.Message);
}
}
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception");
Console.WriteLine(e.Message);

_logger.Fatal(e, "Unexpected exception: {Exception}", e.Message);
}
finally
{
engineChannel.Writer.TryComplete();
uciChannel.Writer.TryComplete();
//source.Cancel();
LogManager.Shutdown(); // Flush and close down internal threads and timers
}
}
}
21 changes: 11 additions & 10 deletions src/Lynx.Dev/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
//FileAndRankMasks();
//EnhancedPawnEvaluation();
//RookEvaluation();
//TranspositionTable();
//TranspositionTableMethod();
//UnmakeMove();
//PieceSquareTables();
//NewMasks();
Expand Down Expand Up @@ -1038,21 +1038,21 @@ static void RookEvaluation()
Console.WriteLine(eval);
}

static void TranspositionTable()
static void TranspositionTableMethod()
{
static void TesSize(int size)
{
Console.WriteLine("Hash: {0} MB", size);
var length = TranspositionTableExtensions.CalculateLength(size);
var length = TranspositionTable.CalculateLength(size);

var lengthMb = length / 1024 / 1024;

Console.WriteLine("TT memory: {0} MB", lengthMb * Marshal.SizeOf(typeof(TranspositionTableElement)));
Console.WriteLine("TT memory: {0} MB", lengthMb * Marshal.SizeOf<TranspositionTableElement>());
Console.WriteLine("TT array length: {0}MB, (0x{1}, {2} items)", lengthMb, length.ToString("X"), length);
Console.WriteLine("TT mask: 0x{0} ({1})\n", (length - 1).ToString("X"), Convert.ToString((length - 1), 2));
Console.WriteLine("TT mask: 0x{0} ({1})\n", (length - 1).ToString("X"), Convert.ToString(length - 1, 2));
}

Console.WriteLine($"{nameof(TranspositionTableElement)} size: {Marshal.SizeOf(typeof(TranspositionTableElement))} bytes\n");
Console.WriteLine($"{nameof(TranspositionTableElement)} size: {Marshal.SizeOf<TranspositionTableElement>()} bytes\n");

TesSize(2);
TesSize(4);
Expand All @@ -1064,19 +1064,20 @@ static void TesSize(int size)
TesSize(512);
TesSize(1024);

var ttLength = TranspositionTableExtensions.CalculateLength(Configuration.EngineSettings.TranspositionTableSize);
var transpositionTable = new TranspositionTableElement[ttLength];
var ttLength = TranspositionTable.CalculateLength(Configuration.EngineSettings.TranspositionTableSize);
var transpositionTable = new TranspositionTable();

var position = new Position(Constants.InitialPositionFEN);
position.Print();
Console.WriteLine($"Hash: {position.UniqueIdentifier}");

var hashKey = position.UniqueIdentifier % 0x400000;
Console.WriteLine(hashKey);

var hashKey2 = TranspositionTableExtensions.CalculateTTIndex(position.UniqueIdentifier, ttLength);
var hashKey2 = transpositionTable.CalculateTTIndex(position.UniqueIdentifier);
Console.WriteLine(hashKey2);

Array.Clear(transpositionTable);
transpositionTable.Reset();

//transpositionTable.RecordHash(position, depth: 3, maxDepth: 5, move: 1234, eval: +5, nodeType: NodeType.Alpha);
//var entry = transpositionTable.ProbeHash(position, maxDepth: 5, depth: 3, alpha: 1, beta: 2);
Expand Down
30 changes: 6 additions & 24 deletions src/Lynx/Engine.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Lynx.Model;
using Lynx.UCI.Commands.Engine;
using Lynx.UCI.Commands.GUI;
using NLog;
using System.Diagnostics;
Expand All @@ -14,6 +13,7 @@ public sealed partial class Engine

private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private readonly ChannelWriter<object> _engineWriter;
private readonly TranspositionTable _tt;

private bool _isSearching;

Expand All @@ -39,24 +39,24 @@ public sealed partial class Engine

public double AverageDepth { get; private set; }

public RegisterCommand? Registration { get; set; }

public Game Game { get; private set; }

public bool PendingConfirmation { get; set; }

private CancellationTokenSource _searchCancellationTokenSource;
private CancellationTokenSource _absoluteSearchCancellationTokenSource;

public Engine(ChannelWriter<object> engineWriter)
public Engine(ChannelWriter<object> engineWriter) : this(engineWriter, new()) { }

public Engine(ChannelWriter<object> engineWriter, TranspositionTable tt)
{
AverageDepth = 0;
Game = new Game(Constants.InitialPositionFEN);
_isNewGameComing = true;
_searchCancellationTokenSource = new();
_absoluteSearchCancellationTokenSource = new();
_engineWriter = engineWriter;

_tt = tt;
// Update ResetEngine() after any changes here

_quietHistory = new int[12][];
Expand All @@ -71,8 +71,6 @@ public Engine(ChannelWriter<object> engineWriter)
_killerMoves[i] = new Move[3];
}

AllocateTT();

#if !DEBUG
// Temporary channel so that no output is generated
_engineWriter = Channel.CreateUnbounded<object>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = false }).Writer;
Expand All @@ -89,14 +87,6 @@ public Engine(ChannelWriter<object> engineWriter)
#pragma warning restore S1215 // "GC.Collect" should not be called
}

private void AllocateTT()
{
_currentTranspositionTableSize = Configuration.EngineSettings.TranspositionTableSize;

var ttLength = TranspositionTableExtensions.CalculateLength(_currentTranspositionTableSize);
_tt = GC.AllocateArray<TranspositionTableElement>(ttLength, pinned: true);
}

#pragma warning disable S1144 // Unused private types or members should be removed - used in Release mode
private void WarmupEngine()
{
Expand All @@ -122,15 +112,7 @@ private void WarmupEngine()

private void ResetEngine()
{
if (_currentTranspositionTableSize == Configuration.EngineSettings.TranspositionTableSize)
{
Array.Clear(_tt);
}
else
{
_logger.Info("Resizing TT ({CurrentSize} MB -> {NewSize} MB)", _currentTranspositionTableSize, Configuration.EngineSettings.TranspositionTableSize);
AllocateTT();
}
_tt.Reset();

// Clear histories
for (int i = 0; i < 12; ++i)
Expand Down
4 changes: 0 additions & 4 deletions src/Lynx/Lynx.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@
<ProjectReference Include="..\Lynx.Generator\Lynx.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>

<ItemGroup>
<Using Include="Lynx.Model.TranspositionTableElement[]" Alias="TranspositionTable" />
</ItemGroup>

<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
Expand Down
2 changes: 2 additions & 0 deletions src/Lynx/Model/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public sealed class Game : IDisposable

public Position PositionBeforeLastSearch { get; private set; }

public string FEN => CurrentPosition.FEN(HalfMovesWithoutCaptureOrPawnMove);

public Game(ReadOnlySpan<char> fen) : this(fen, [], [], [])
{
}
Expand Down
Loading
Loading