mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-23 05:07:14 +00:00
Consistent Integer Types
example of using, to avoid mixed usage of std::uint/std::int and uint/int... ```cpp using u64 = std::uint64_t; using u32 = std::uint32_t; using u16 = std::uint16_t; using u8 = std::uint8_t; using i64 = std::int64_t; using i32 = std::int32_t; using i16 = std::int16_t; using i8 = std::int8_t; using usize = std::size_t; using isize = std::ptrdiff_t; #if defined(__GNUC__) && defined(IS_64BIT) __extension__ using u128 = unsigned __int128; __extension__ using i128 = signed __int128; #endif ``` closes https://github.com/official-stockfish/Stockfish/pull/6874 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
e4a635486a
commit
dd3e1c4a50
+7
-7
@@ -39,7 +39,7 @@ alignas(64) Magic Magics[SQUARE_NB][2];
|
||||
}
|
||||
|
||||
#ifdef USE_PEXT
|
||||
using MagicMask = uint16_t;
|
||||
using MagicMask = u16;
|
||||
#else
|
||||
using MagicMask = Bitboard;
|
||||
#endif
|
||||
@@ -77,10 +77,10 @@ static void init_magics(Magic magics[][2]) {
|
||||
// Sliding attacks within a rank, indexed by the slider's file and the
|
||||
// 8-bit rank occupancy, yielding the 8-bit attack set on that rank
|
||||
constexpr auto RankAttacks = []() {
|
||||
std::array<std::array<uint8_t, 256>, FILE_NB> table{};
|
||||
std::array<std::array<u8, 256>, FILE_NB> table{};
|
||||
for (int file = 0; file < 8; ++file)
|
||||
for (int occ = 0; occ < 256; ++occ)
|
||||
table[file][occ] = uint8_t(sliding_attack(ROOK, Square(file), occ));
|
||||
table[file][occ] = u8(sliding_attack(ROOK, Square(file), occ));
|
||||
return table;
|
||||
}();
|
||||
|
||||
@@ -198,14 +198,14 @@ constexpr
|
||||
|
||||
#if defined(USE_COMPTIME_ATTACKS) && defined(USE_PEXT)
|
||||
constexpr auto RookTable = []() {
|
||||
std::array<uint16_t, 0x19000> result{};
|
||||
Magic magics[64][2] = {};
|
||||
std::array<u16, 0x19000> result{};
|
||||
Magic magics[64][2] = {};
|
||||
init_magics(ROOK, result.data(), magics, false);
|
||||
return result;
|
||||
}();
|
||||
constexpr auto BishopTable = []() {
|
||||
std::array<uint16_t, 0x1480> result{};
|
||||
Magic magics[64][2] = {};
|
||||
std::array<u16, 0x1480> result{};
|
||||
Magic magics[64][2] = {};
|
||||
init_magics(BISHOP, result.data(), magics, false);
|
||||
return result;
|
||||
}();
|
||||
|
||||
+3
-3
@@ -81,7 +81,7 @@ struct DualMagic {
|
||||
// Precomputed 2 * square_bb(sq), 2 * reverse(square_bb(sq))
|
||||
Bitboard r, rr;
|
||||
|
||||
const uint8_t* RESTRICT rankAttacksLookup;
|
||||
const u8* RESTRICT rankAttacksLookup;
|
||||
// 8 * rank_of(sq)
|
||||
int shift;
|
||||
|
||||
@@ -130,8 +130,8 @@ const DualMagic& dual_magic(Square s);
|
||||
struct Magic {
|
||||
Bitboard mask;
|
||||
#ifdef USE_PEXT
|
||||
uint16_t* attacks;
|
||||
Bitboard pseudoAttacks;
|
||||
u16* attacks;
|
||||
Bitboard pseudoAttacks;
|
||||
#else
|
||||
Bitboard* attacks;
|
||||
Bitboard magic;
|
||||
|
||||
+3
-3
@@ -22,8 +22,8 @@
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
uint8_t PopCnt16[1 << 16];
|
||||
uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
||||
u8 PopCnt16[1 << 16];
|
||||
u8 SquareDistance[SQUARE_NB][SQUARE_NB];
|
||||
|
||||
// Returns an ASCII representation of a bitboard suitable
|
||||
// to be printed to standard output. Useful for debugging.
|
||||
@@ -51,7 +51,7 @@ std::string Bitboards::pretty(Bitboard b) {
|
||||
void Bitboards::init() {
|
||||
|
||||
for (unsigned i = 0; i < (1 << 16); ++i)
|
||||
PopCnt16[i] = uint8_t(std::bitset<16>(i).count());
|
||||
PopCnt16[i] = u8(std::bitset<16>(i).count());
|
||||
|
||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
||||
|
||||
+10
-10
@@ -23,11 +23,11 @@
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#include "types.h"
|
||||
#include "misc.h"
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
@@ -65,8 +65,8 @@ constexpr Bitboard Rank6BB = Rank1BB << (8 * 5);
|
||||
constexpr Bitboard Rank7BB = Rank1BB << (8 * 6);
|
||||
constexpr Bitboard Rank8BB = Rank1BB << (8 * 7);
|
||||
|
||||
extern uint8_t PopCnt16[1 << 16];
|
||||
extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB];
|
||||
extern u8 PopCnt16[1 << 16];
|
||||
extern u8 SquareDistance[SQUARE_NB][SQUARE_NB];
|
||||
|
||||
constexpr Bitboard square_bb(Square s) {
|
||||
assert(is_ok(s));
|
||||
@@ -169,7 +169,7 @@ inline int popcount(Bitboard b) {
|
||||
|
||||
#ifndef USE_POPCNT
|
||||
|
||||
std::uint16_t indices[4];
|
||||
u16 indices[4];
|
||||
std::memcpy(indices, &b, sizeof(b));
|
||||
return PopCnt16[indices[0]] + PopCnt16[indices[1]] + PopCnt16[indices[2]]
|
||||
+ PopCnt16[indices[3]];
|
||||
@@ -190,9 +190,9 @@ inline constexpr int lsb_index64[64] = {
|
||||
21, 44, 38, 32, 29, 23, 17, 11, 4, 62, 46, 55, 26, 59, 40, 36, 15, 53, 34, 51, 20, 43,
|
||||
31, 22, 10, 45, 25, 39, 14, 33, 19, 30, 9, 24, 13, 18, 8, 12, 7, 6, 5, 63};
|
||||
|
||||
constexpr int constexpr_lsb(uint64_t bb) {
|
||||
constexpr int constexpr_lsb(u64 bb) {
|
||||
assert(bb != 0);
|
||||
constexpr uint64_t debruijn64 = 0x03F79D71B4CB0A89ULL;
|
||||
constexpr u64 debruijn64 = 0x03F79D71B4CB0A89ULL;
|
||||
return lsb_index64[((bb ^ (bb - 1)) * debruijn64) >> 58];
|
||||
}
|
||||
|
||||
@@ -216,12 +216,12 @@ inline Square lsb(Bitboard b) {
|
||||
|
||||
if (b & 0xffffffff)
|
||||
{
|
||||
_BitScanForward(&idx, int32_t(b));
|
||||
_BitScanForward(&idx, i32(b));
|
||||
return Square(idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
_BitScanForward(&idx, int32_t(b >> 32));
|
||||
_BitScanForward(&idx, i32(b >> 32));
|
||||
return Square(idx + 32);
|
||||
}
|
||||
#endif
|
||||
@@ -251,12 +251,12 @@ inline Square msb(Bitboard b) {
|
||||
|
||||
if (b >> 32)
|
||||
{
|
||||
_BitScanReverse(&idx, int32_t(b >> 32));
|
||||
_BitScanReverse(&idx, i32(b >> 32));
|
||||
return Square(idx + 32);
|
||||
}
|
||||
else
|
||||
{
|
||||
_BitScanReverse(&idx, int32_t(b));
|
||||
_BitScanReverse(&idx, i32(b));
|
||||
return Square(idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
+9
-9
@@ -142,7 +142,7 @@ Engine::Engine(std::optional<std::string> path) :
|
||||
resize_threads();
|
||||
}
|
||||
|
||||
std::uint64_t Engine::perft(const std::string& fen, Depth depth, bool isChess960) {
|
||||
u64 Engine::perft(const std::string& fen, Depth depth, bool isChess960) {
|
||||
verify_network();
|
||||
|
||||
return Benchmark::perft(fen, depth, isChess960);
|
||||
@@ -246,7 +246,7 @@ void Engine::resize_threads() {
|
||||
threads.ensure_network_replicated();
|
||||
}
|
||||
|
||||
void Engine::set_tt_size(size_t mb) {
|
||||
void Engine::set_tt_size(usize mb) {
|
||||
wait_for_search_finished();
|
||||
tt.resize(mb, threads);
|
||||
}
|
||||
@@ -259,7 +259,7 @@ void Engine::verify_network() const {
|
||||
network->verify(options["EvalFile"], onVerifyNetwork);
|
||||
|
||||
auto statuses = network.get_status_and_errors();
|
||||
for (size_t i = 0; i < statuses.size(); ++i)
|
||||
for (usize i = 0; i < statuses.size(); ++i)
|
||||
{
|
||||
const auto [status, error] = statuses[i];
|
||||
std::string message = "Network replica " + std::to_string(i + 1) + ": ";
|
||||
@@ -336,11 +336,11 @@ std::string Engine::visualize() const {
|
||||
|
||||
int Engine::get_hashfull(int maxAge) const { return tt.hashfull(maxAge); }
|
||||
|
||||
std::vector<std::pair<size_t, size_t>> Engine::get_bound_thread_count_by_numa_node() const {
|
||||
auto counts = threads.get_bound_thread_count_by_numa_node();
|
||||
const NumaConfig& cfg = numaContext.get_numa_config();
|
||||
std::vector<std::pair<size_t, size_t>> ratios;
|
||||
NumaIndex n = 0;
|
||||
std::vector<std::pair<usize, usize>> Engine::get_bound_thread_count_by_numa_node() const {
|
||||
auto counts = threads.get_bound_thread_count_by_numa_node();
|
||||
const NumaConfig& cfg = numaContext.get_numa_config();
|
||||
std::vector<std::pair<usize, usize>> ratios;
|
||||
NumaIndex n = 0;
|
||||
for (; n < counts.size(); ++n)
|
||||
ratios.emplace_back(counts[n], cfg.num_cpus_in_numa_node(n));
|
||||
if (!counts.empty())
|
||||
@@ -380,7 +380,7 @@ std::string Engine::thread_binding_information_as_string() const {
|
||||
std::string Engine::thread_allocation_information_as_string() const {
|
||||
std::stringstream ss;
|
||||
|
||||
size_t threadsSize = threads.size();
|
||||
usize threadsSize = threads.size();
|
||||
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");
|
||||
|
||||
auto boundThreadsByNodeStr = thread_binding_information_as_string();
|
||||
|
||||
+11
-12
@@ -19,8 +19,6 @@
|
||||
#ifndef ENGINE_H_INCLUDED
|
||||
#define ENGINE_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -30,6 +28,7 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "misc.h"
|
||||
#include "history.h"
|
||||
#include "nnue/network.h"
|
||||
#include "numa.h"
|
||||
@@ -58,7 +57,7 @@ class Engine {
|
||||
|
||||
~Engine() { wait_for_search_finished(); }
|
||||
|
||||
std::uint64_t perft(const std::string& fen, Depth depth, bool isChess960);
|
||||
u64 perft(const std::string& fen, Depth depth, bool isChess960);
|
||||
|
||||
// non blocking call to start searching
|
||||
void go(Search::LimitsType&);
|
||||
@@ -75,7 +74,7 @@ class Engine {
|
||||
|
||||
void set_numa_config_from_option(const std::string& o);
|
||||
void resize_threads();
|
||||
void set_tt_size(size_t mb);
|
||||
void set_tt_size(usize mb);
|
||||
void set_ponderhit(bool);
|
||||
void search_clear();
|
||||
|
||||
@@ -101,14 +100,14 @@ class Engine {
|
||||
|
||||
int get_hashfull(int maxAge = 0) const;
|
||||
|
||||
std::string fen() const;
|
||||
void flip();
|
||||
std::string visualize() const;
|
||||
std::vector<std::pair<size_t, size_t>> get_bound_thread_count_by_numa_node() const;
|
||||
std::string get_numa_config_as_string() const;
|
||||
std::string numa_config_information_as_string() const;
|
||||
std::string thread_allocation_information_as_string() const;
|
||||
std::string thread_binding_information_as_string() const;
|
||||
std::string fen() const;
|
||||
void flip();
|
||||
std::string visualize() const;
|
||||
std::vector<std::pair<usize, usize>> get_bound_thread_count_by_numa_node() const;
|
||||
std::string get_numa_config_as_string() const;
|
||||
std::string numa_config_information_as_string() const;
|
||||
std::string thread_allocation_information_as_string() const;
|
||||
std::string thread_binding_information_as_string() const;
|
||||
|
||||
private:
|
||||
const std::string binaryDirectory;
|
||||
|
||||
+22
-23
@@ -36,7 +36,7 @@
|
||||
namespace Stockfish {
|
||||
|
||||
constexpr int PAWN_HISTORY_BASE_SIZE = 8192; // has to be a power of 2
|
||||
constexpr int UINT_16_HISTORY_SIZE = std::numeric_limits<uint16_t>::max() + 1;
|
||||
constexpr int UINT_16_HISTORY_SIZE = std::numeric_limits<u16>::max() + 1;
|
||||
constexpr int CORRHIST_BASE_SIZE = UINT_16_HISTORY_SIZE;
|
||||
constexpr int CORRECTION_HISTORY_LIMIT = 1024;
|
||||
constexpr int LOW_PLY_HISTORY_SIZE = 5;
|
||||
@@ -89,10 +89,10 @@ enum StatsType {
|
||||
Captures
|
||||
};
|
||||
|
||||
template<typename T, int D, std::size_t... Sizes>
|
||||
template<typename T, int D, usize... Sizes>
|
||||
using Stats = MultiArray<StatsEntry<T, D>, Sizes...>;
|
||||
|
||||
template<typename T, int D, std::size_t... Sizes>
|
||||
template<typename T, int D, usize... Sizes>
|
||||
using AtomicStats = MultiArray<StatsEntry<T, D, true>, Sizes...>;
|
||||
|
||||
// DynStats is a dynamically sized array of Stats, used for thread-shared histories
|
||||
@@ -100,31 +100,31 @@ using AtomicStats = MultiArray<StatsEntry<T, D, true>, Sizes...>;
|
||||
// the per-thread allocation count of T.
|
||||
template<typename T, int SizeMultiplier>
|
||||
struct DynStats {
|
||||
explicit DynStats(size_t s) {
|
||||
explicit DynStats(usize s) {
|
||||
size = s * SizeMultiplier;
|
||||
data = make_unique_large_page<T[]>(size);
|
||||
}
|
||||
// Sets all values in the range to 0
|
||||
void clear_range(int value, size_t threadIdx, size_t numaTotal) {
|
||||
size_t start = uint64_t(threadIdx) * size / numaTotal;
|
||||
void clear_range(int value, usize threadIdx, usize numaTotal) {
|
||||
usize start = u64(threadIdx) * size / numaTotal;
|
||||
assert(start < size);
|
||||
size_t end = threadIdx + 1 == numaTotal ? size : uint64_t(threadIdx + 1) * size / numaTotal;
|
||||
usize end = threadIdx + 1 == numaTotal ? size : u64(threadIdx + 1) * size / numaTotal;
|
||||
|
||||
while (start < end)
|
||||
data[start++].fill(value);
|
||||
}
|
||||
size_t get_size() const { return size; }
|
||||
T& operator[](size_t index) {
|
||||
usize get_size() const { return size; }
|
||||
T& operator[](usize index) {
|
||||
assert(index < size);
|
||||
return data.get()[index];
|
||||
}
|
||||
const T& operator[](size_t index) const {
|
||||
const T& operator[](usize index) const {
|
||||
assert(index < size);
|
||||
return data.get()[index];
|
||||
}
|
||||
|
||||
private:
|
||||
size_t size;
|
||||
usize size;
|
||||
LargePagePtr<T[]> data;
|
||||
};
|
||||
|
||||
@@ -132,17 +132,17 @@ struct DynStats {
|
||||
// during the current search, and is used for reduction and move ordering decisions.
|
||||
// It uses 2 tables (one for each color) indexed by the move's from and to squares,
|
||||
// see https://www.chessprogramming.org/Butterfly_Boards
|
||||
using ButterflyHistory = Stats<std::int16_t, 7183, COLOR_NB, UINT_16_HISTORY_SIZE>;
|
||||
using ButterflyHistory = Stats<i16, 7183, COLOR_NB, UINT_16_HISTORY_SIZE>;
|
||||
|
||||
// LowPlyHistory is addressed by ply and move's from and to squares, used
|
||||
// to improve move ordering near the root
|
||||
using LowPlyHistory = Stats<std::int16_t, 7183, LOW_PLY_HISTORY_SIZE, UINT_16_HISTORY_SIZE>;
|
||||
using LowPlyHistory = Stats<i16, 7183, LOW_PLY_HISTORY_SIZE, UINT_16_HISTORY_SIZE>;
|
||||
|
||||
// CapturePieceToHistory is addressed by a move's [piece][to][captured piece type]
|
||||
using CapturePieceToHistory = Stats<std::int16_t, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
|
||||
using CapturePieceToHistory = Stats<i16, 10692, PIECE_NB, SQUARE_NB, PIECE_TYPE_NB>;
|
||||
|
||||
// PieceToHistory is like ButterflyHistory but is addressed by a move's [piece][to]
|
||||
using PieceToHistory = Stats<std::int16_t, 30000, PIECE_NB, SQUARE_NB>;
|
||||
using PieceToHistory = Stats<i16, 30000, PIECE_NB, SQUARE_NB>;
|
||||
|
||||
// ContinuationHistory is the combined history of a given pair of moves, usually
|
||||
// the current one given a previous one. The nested history table is based on
|
||||
@@ -150,8 +150,7 @@ using PieceToHistory = Stats<std::int16_t, 30000, PIECE_NB, SQUARE_NB>;
|
||||
using ContinuationHistory = MultiArray<PieceToHistory, PIECE_NB, SQUARE_NB>;
|
||||
|
||||
// PawnHistory is addressed by the pawn structure and a move's [piece][to]
|
||||
using PawnHistory =
|
||||
DynStats<AtomicStats<std::int16_t, 8192, PIECE_NB, SQUARE_NB>, PAWN_HISTORY_BASE_SIZE>;
|
||||
using PawnHistory = DynStats<AtomicStats<i16, 8192, PIECE_NB, SQUARE_NB>, PAWN_HISTORY_BASE_SIZE>;
|
||||
|
||||
// Correction histories record differences between the static evaluation of
|
||||
// positions and their search score. It is used to improve the static evaluation
|
||||
@@ -184,7 +183,7 @@ struct CorrHistTypedef;
|
||||
|
||||
template<>
|
||||
struct CorrHistTypedef<PieceTo> {
|
||||
using type = Stats<std::int16_t, CORRECTION_HISTORY_LIMIT, PIECE_NB, SQUARE_NB>;
|
||||
using type = Stats<i16, CORRECTION_HISTORY_LIMIT, PIECE_NB, SQUARE_NB>;
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -195,20 +194,20 @@ struct CorrHistTypedef<Continuation> {
|
||||
}
|
||||
|
||||
using UnifiedCorrectionHistory =
|
||||
DynStats<MultiArray<CorrectionBundle<std::int16_t, CORRECTION_HISTORY_LIMIT>, COLOR_NB>,
|
||||
DynStats<MultiArray<CorrectionBundle<i16, CORRECTION_HISTORY_LIMIT>, COLOR_NB>,
|
||||
CORRHIST_BASE_SIZE>;
|
||||
|
||||
template<CorrHistType T>
|
||||
using CorrectionHistory = typename Detail::CorrHistTypedef<T>::type;
|
||||
|
||||
using TTMoveHistory = StatsEntry<std::int16_t, 8192>;
|
||||
using TTMoveHistory = StatsEntry<i16, 8192>;
|
||||
|
||||
// Set of histories shared between groups of threads. To avoid excessive
|
||||
// cross-node data transfer, histories are shared only between threads
|
||||
// on a given NUMA node. The passed size must be a power of two to make
|
||||
// the indexing more efficient.
|
||||
struct SharedHistories {
|
||||
SharedHistories(size_t threadCount) :
|
||||
SharedHistories(usize threadCount) :
|
||||
correctionHistory(threadCount),
|
||||
pawnHistory(threadCount) {
|
||||
assert((threadCount & (threadCount - 1)) == 0 && threadCount != 0);
|
||||
@@ -216,7 +215,7 @@ struct SharedHistories {
|
||||
pawnHistSizeMinus1 = pawnHistory.get_size() - 1;
|
||||
}
|
||||
|
||||
size_t get_size() const { return sizeMinus1 + 1; }
|
||||
usize get_size() const { return sizeMinus1 + 1; }
|
||||
|
||||
auto& pawn_entry(const Position& pos) {
|
||||
return pawnHistory[pos.pawn_key() & pawnHistSizeMinus1];
|
||||
@@ -253,7 +252,7 @@ struct SharedHistories {
|
||||
|
||||
|
||||
private:
|
||||
size_t sizeMinus1, pawnHistSizeMinus1;
|
||||
usize sizeMinus1, pawnHistSizeMinus1;
|
||||
};
|
||||
|
||||
} // namespace Stockfish
|
||||
|
||||
+28
-28
@@ -294,17 +294,17 @@ constexpr int MaxDebugSlots = 32;
|
||||
|
||||
namespace {
|
||||
|
||||
template<size_t N>
|
||||
template<usize N>
|
||||
struct DebugInfo {
|
||||
std::array<std::atomic<int64_t>, N> data = {0};
|
||||
std::array<std::atomic<i64>, N> data = {0};
|
||||
|
||||
[[nodiscard]] constexpr std::atomic<int64_t>& operator[](size_t index) {
|
||||
[[nodiscard]] constexpr std::atomic<i64>& operator[](usize index) {
|
||||
assert(index < N);
|
||||
return data[index];
|
||||
}
|
||||
|
||||
constexpr DebugInfo& operator=(const DebugInfo& other) {
|
||||
for (size_t i = 0; i < N; i++)
|
||||
for (usize i = 0; i < N; i++)
|
||||
data[i].store(other.data[i].load());
|
||||
return *this;
|
||||
}
|
||||
@@ -312,8 +312,8 @@ struct DebugInfo {
|
||||
|
||||
struct DebugExtremes: public DebugInfo<3> {
|
||||
DebugExtremes() {
|
||||
data[1] = std::numeric_limits<int64_t>::min();
|
||||
data[2] = std::numeric_limits<int64_t>::max();
|
||||
data[1] = std::numeric_limits<i64>::min();
|
||||
data[2] = std::numeric_limits<i64>::max();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -332,32 +332,32 @@ void dbg_hit_on(bool cond, int slot) {
|
||||
++hit.at(slot)[1];
|
||||
}
|
||||
|
||||
void dbg_mean_of(int64_t value, int slot) {
|
||||
void dbg_mean_of(i64 value, int slot) {
|
||||
|
||||
++mean.at(slot)[0];
|
||||
mean.at(slot)[1] += value;
|
||||
}
|
||||
|
||||
void dbg_stdev_of(int64_t value, int slot) {
|
||||
void dbg_stdev_of(i64 value, int slot) {
|
||||
|
||||
++stdev.at(slot)[0];
|
||||
stdev.at(slot)[1] += value;
|
||||
stdev.at(slot)[2] += value * value;
|
||||
}
|
||||
|
||||
void dbg_extremes_of(int64_t value, int slot) {
|
||||
void dbg_extremes_of(i64 value, int slot) {
|
||||
++extremes.at(slot)[0];
|
||||
|
||||
int64_t current_max = extremes.at(slot)[1].load();
|
||||
i64 current_max = extremes.at(slot)[1].load();
|
||||
while (current_max < value && !extremes.at(slot)[1].compare_exchange_weak(current_max, value))
|
||||
{}
|
||||
|
||||
int64_t current_min = extremes.at(slot)[2].load();
|
||||
i64 current_min = extremes.at(slot)[2].load();
|
||||
while (current_min > value && !extremes.at(slot)[2].compare_exchange_weak(current_min, value))
|
||||
{}
|
||||
}
|
||||
|
||||
void dbg_correl_of(int64_t value1, int64_t value2, int slot) {
|
||||
void dbg_correl_of(i64 value1, i64 value2, int slot) {
|
||||
|
||||
++correl.at(slot)[0];
|
||||
correl.at(slot)[1] += value1;
|
||||
@@ -369,9 +369,9 @@ void dbg_correl_of(int64_t value1, int64_t value2, int slot) {
|
||||
|
||||
void dbg_print() {
|
||||
|
||||
int64_t n;
|
||||
auto E = [&n](int64_t x) { return double(x) / n; };
|
||||
auto sqr = [](double x) { return x * x; };
|
||||
i64 n;
|
||||
auto E = [&n](i64 x) { return double(x) / n; };
|
||||
auto sqr = [](double x) { return x * x; };
|
||||
|
||||
for (int i = 0; i < MaxDebugSlots; ++i)
|
||||
if ((n = hit[i][0]))
|
||||
@@ -435,17 +435,17 @@ void sync_cout_start() { std::cout << IO_LOCK; }
|
||||
void sync_cout_end() { std::cout << IO_UNLOCK; }
|
||||
|
||||
// Hash function based on public domain MurmurHash64A, by Austin Appleby.
|
||||
uint64_t hash_bytes(const char* data, size_t size) {
|
||||
const uint64_t m = 0xc6a4a7935bd1e995ull;
|
||||
const int r = 47;
|
||||
u64 hash_bytes(const char* data, usize size) {
|
||||
const u64 m = 0xc6a4a7935bd1e995ull;
|
||||
const int r = 47;
|
||||
|
||||
uint64_t h = size * m;
|
||||
u64 h = size * m;
|
||||
|
||||
const char* end = data + (size & ~(size_t) 7);
|
||||
const char* end = data + (size & ~(usize) 7);
|
||||
|
||||
for (const char* p = data; p != end; p += 8)
|
||||
{
|
||||
uint64_t k;
|
||||
u64 k;
|
||||
std::memcpy(&k, p, sizeof(k));
|
||||
|
||||
k *= m;
|
||||
@@ -458,9 +458,9 @@ uint64_t hash_bytes(const char* data, size_t size) {
|
||||
|
||||
if (size & 7)
|
||||
{
|
||||
uint64_t k = 0;
|
||||
u64 k = 0;
|
||||
for (int i = (size & 7) - 1; i >= 0; i--)
|
||||
k = (k << 8) | (uint64_t) end[i];
|
||||
k = (k << 8) | u64(end[i]);
|
||||
|
||||
h ^= k;
|
||||
h *= m;
|
||||
@@ -485,11 +485,11 @@ void start_logger(const std::string& fname) { Logger::start(fname); }
|
||||
#define GETCWD getcwd
|
||||
#endif
|
||||
|
||||
size_t str_to_size_t(const std::string& s) {
|
||||
usize str_to_size_t(const std::string& s) {
|
||||
unsigned long long value = std::stoull(s);
|
||||
if (value > std::numeric_limits<size_t>::max())
|
||||
if (value > std::numeric_limits<usize>::max())
|
||||
std::exit(EXIT_FAILURE);
|
||||
return static_cast<size_t>(value);
|
||||
return static_cast<usize>(value);
|
||||
}
|
||||
|
||||
std::optional<std::string> read_file_to_string(const std::string& path) {
|
||||
@@ -527,8 +527,8 @@ std::string CommandLine::get_binary_directory(std::string argv0) {
|
||||
auto workingDirectory = CommandLine::get_working_directory();
|
||||
|
||||
// Extract the binary directory path from argv0
|
||||
auto binaryDirectory = argv0;
|
||||
size_t pos = binaryDirectory.find_last_of("\\/");
|
||||
auto binaryDirectory = argv0;
|
||||
usize pos = binaryDirectory.find_last_of("\\/");
|
||||
if (pos == std::string::npos)
|
||||
binaryDirectory = "." + pathSeparator;
|
||||
else
|
||||
|
||||
+67
-50
@@ -23,6 +23,7 @@
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <exception> // IWYU pragma: keep
|
||||
@@ -46,6 +47,24 @@
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
using u64 = std::uint64_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u8 = std::uint8_t;
|
||||
|
||||
using i64 = std::int64_t;
|
||||
using i32 = std::int32_t;
|
||||
using i16 = std::int16_t;
|
||||
using i8 = std::int8_t;
|
||||
|
||||
using usize = std::size_t;
|
||||
using isize = std::ptrdiff_t;
|
||||
|
||||
#if defined(__GNUC__) && defined(IS_64BIT)
|
||||
__extension__ using u128 = unsigned __int128;
|
||||
__extension__ using i128 = signed __int128;
|
||||
#endif
|
||||
|
||||
std::string engine_version_info();
|
||||
std::string engine_info(bool to_uci = false);
|
||||
std::string compiler_info();
|
||||
@@ -114,7 +133,7 @@ void prefetch(const void* addr) {
|
||||
|
||||
void start_logger(const std::string& fname);
|
||||
|
||||
size_t str_to_size_t(const std::string& s);
|
||||
usize str_to_size_t(const std::string& s);
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
@@ -134,15 +153,15 @@ struct PipeDeleter {
|
||||
std::optional<std::string> read_file_to_string(const std::string& path);
|
||||
|
||||
void dbg_hit_on(bool cond, int slot = 0);
|
||||
void dbg_mean_of(int64_t value, int slot = 0);
|
||||
void dbg_stdev_of(int64_t value, int slot = 0);
|
||||
void dbg_extremes_of(int64_t value, int slot = 0);
|
||||
void dbg_correl_of(int64_t value1, int64_t value2, int slot = 0);
|
||||
void dbg_mean_of(i64 value, int slot = 0);
|
||||
void dbg_stdev_of(i64 value, int slot = 0);
|
||||
void dbg_extremes_of(i64 value, int slot = 0);
|
||||
void dbg_correl_of(i64 value1, i64 value2, int slot = 0);
|
||||
void dbg_print();
|
||||
void dbg_clear();
|
||||
|
||||
using TimePoint = std::chrono::milliseconds::rep; // A value in milliseconds
|
||||
static_assert(sizeof(TimePoint) == sizeof(int64_t), "TimePoint should be 64 bits");
|
||||
static_assert(sizeof(TimePoint) == sizeof(i64), "TimePoint should be 64 bits");
|
||||
inline TimePoint now() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch())
|
||||
@@ -155,10 +174,10 @@ inline std::vector<std::string_view> split(std::string_view s, std::string_view
|
||||
if (s.empty())
|
||||
return res;
|
||||
|
||||
size_t begin = 0;
|
||||
usize begin = 0;
|
||||
for (;;)
|
||||
{
|
||||
const size_t end = s.find(delimiter, begin);
|
||||
const usize end = s.find(delimiter, begin);
|
||||
if (end == std::string::npos)
|
||||
break;
|
||||
|
||||
@@ -187,17 +206,17 @@ void sync_cout_start();
|
||||
void sync_cout_end();
|
||||
|
||||
// True if and only if the binary is compiled on a little-endian machine
|
||||
static inline const std::uint16_t Le = 1;
|
||||
static inline const bool IsLittleEndian = *reinterpret_cast<const char*>(&Le) == 1;
|
||||
static inline const u16 Le = 1;
|
||||
static inline const bool IsLittleEndian = *reinterpret_cast<const char*>(&Le) == 1;
|
||||
|
||||
|
||||
template<typename T, std::size_t MaxSize>
|
||||
template<typename T, usize MaxSize>
|
||||
class ValueList {
|
||||
|
||||
public:
|
||||
std::size_t size() const { return size_; }
|
||||
int ssize() const { return int(size_); }
|
||||
void push_back(const T& value) {
|
||||
usize size() const { return size_; }
|
||||
int ssize() const { return int(size_); }
|
||||
void push_back(const T& value) {
|
||||
assert(size_ < MaxSize);
|
||||
values_[size_++] = value;
|
||||
}
|
||||
@@ -211,7 +230,7 @@ class ValueList {
|
||||
const T* end() const { return values_ + size_; }
|
||||
const T& operator[](int index) const { return values_[index]; }
|
||||
|
||||
T* make_space(size_t count) {
|
||||
T* make_space(usize count) {
|
||||
T* result = &values_[size_];
|
||||
size_ += count;
|
||||
assert(size_ <= MaxSize);
|
||||
@@ -219,22 +238,22 @@ class ValueList {
|
||||
}
|
||||
|
||||
private:
|
||||
T values_[MaxSize];
|
||||
std::size_t size_ = 0;
|
||||
T values_[MaxSize];
|
||||
usize size_ = 0;
|
||||
};
|
||||
|
||||
|
||||
template<typename T, std::size_t Size, std::size_t... Sizes>
|
||||
template<typename T, usize Size, usize... Sizes>
|
||||
class MultiArray;
|
||||
|
||||
namespace Detail {
|
||||
|
||||
template<typename T, std::size_t Size, std::size_t... Sizes>
|
||||
template<typename T, usize Size, usize... Sizes>
|
||||
struct MultiArrayHelper {
|
||||
using ChildType = MultiArray<T, Sizes...>;
|
||||
};
|
||||
|
||||
template<typename T, std::size_t Size>
|
||||
template<typename T, usize Size>
|
||||
struct MultiArrayHelper<T, Size> {
|
||||
using ChildType = T;
|
||||
};
|
||||
@@ -247,7 +266,7 @@ constexpr bool is_strictly_assignable_v =
|
||||
|
||||
// MultiArray is a generic N-dimensional array.
|
||||
// The template parameters (Size and Sizes) encode the dimensions of the array.
|
||||
template<typename T, std::size_t Size, std::size_t... Sizes>
|
||||
template<typename T, usize Size, usize... Sizes>
|
||||
class MultiArray {
|
||||
using ChildType = typename Detail::MultiArrayHelper<T, Size, Sizes...>::ChildType;
|
||||
using ArrayType = std::array<ChildType, Size>;
|
||||
@@ -338,16 +357,16 @@ class MultiArray {
|
||||
|
||||
class PRNG {
|
||||
|
||||
uint64_t s;
|
||||
u64 s;
|
||||
|
||||
uint64_t rand64() {
|
||||
u64 rand64() {
|
||||
|
||||
s ^= s >> 12, s ^= s << 25, s ^= s >> 27;
|
||||
return s * 2685821657736338717LL;
|
||||
}
|
||||
|
||||
public:
|
||||
PRNG(uint64_t seed) :
|
||||
PRNG(u64 seed) :
|
||||
s(seed) {
|
||||
assert(seed);
|
||||
}
|
||||
@@ -365,16 +384,15 @@ class PRNG {
|
||||
}
|
||||
};
|
||||
|
||||
inline uint64_t mul_hi64(uint64_t a, uint64_t b) {
|
||||
inline u64 mul_hi64(u64 a, u64 b) {
|
||||
#if defined(__GNUC__) && defined(IS_64BIT)
|
||||
__extension__ using uint128 = unsigned __int128;
|
||||
return (uint128(a) * uint128(b)) >> 64;
|
||||
return (u128(a) * u128(b)) >> 64;
|
||||
#else
|
||||
uint64_t aL = uint32_t(a), aH = a >> 32;
|
||||
uint64_t bL = uint32_t(b), bH = b >> 32;
|
||||
uint64_t c1 = (aL * bL) >> 32;
|
||||
uint64_t c2 = aH * bL + c1;
|
||||
uint64_t c3 = aL * bH + uint32_t(c2);
|
||||
u64 aL = u32(a), aH = a >> 32;
|
||||
u64 bL = u32(b), bH = b >> 32;
|
||||
u64 c1 = (aL * bL) >> 32;
|
||||
u64 c2 = aH * bL + c1;
|
||||
u64 c3 = aL * bH + u32(c2);
|
||||
return aH * bH + (c2 >> 32) + (c3 >> 32);
|
||||
#endif
|
||||
}
|
||||
@@ -385,20 +403,19 @@ inline constexpr T2 interpolate(T1 x, T1 x0, T1 x1, T2 y0, T2 y1) {
|
||||
return T2(y0 + (y1 - y0) * (x - x0) / (x1 - x0));
|
||||
}
|
||||
|
||||
uint64_t hash_bytes(const char*, size_t);
|
||||
u64 hash_bytes(const char*, usize);
|
||||
|
||||
template<typename T>
|
||||
inline std::size_t get_raw_data_hash(const T& value) {
|
||||
inline usize get_raw_data_hash(const T& value) {
|
||||
// We must have no padding bytes because we're reinterpreting as char
|
||||
static_assert(std::has_unique_object_representations<T>());
|
||||
|
||||
return static_cast<std::size_t>(
|
||||
hash_bytes(reinterpret_cast<const char*>(&value), sizeof(value)));
|
||||
return static_cast<usize>(hash_bytes(reinterpret_cast<const char*>(&value), sizeof(value)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void hash_combine(std::size_t& seed, const T& v) {
|
||||
std::size_t x;
|
||||
inline void hash_combine(usize& seed, const T& v) {
|
||||
usize x;
|
||||
// For primitive types we avoid using the default hasher, which may be
|
||||
// nondeterministic across program invocations
|
||||
if constexpr (std::is_integral<T>())
|
||||
@@ -408,9 +425,9 @@ inline void hash_combine(std::size_t& seed, const T& v) {
|
||||
seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
inline std::uint64_t hash_string(const std::string& sv) { return hash_bytes(sv.data(), sv.size()); }
|
||||
inline u64 hash_string(const std::string& sv) { return hash_bytes(sv.data(), sv.size()); }
|
||||
|
||||
template<std::size_t Capacity>
|
||||
template<usize Capacity>
|
||||
class FixedString {
|
||||
public:
|
||||
FixedString() :
|
||||
@@ -419,7 +436,7 @@ class FixedString {
|
||||
}
|
||||
|
||||
FixedString(const char* str) {
|
||||
size_t len = std::strlen(str);
|
||||
usize len = std::strlen(str);
|
||||
if (len > Capacity)
|
||||
std::terminate();
|
||||
std::memcpy(data_, str, len);
|
||||
@@ -435,18 +452,18 @@ class FixedString {
|
||||
data_[length_] = '\0';
|
||||
}
|
||||
|
||||
std::size_t size() const { return length_; }
|
||||
std::size_t capacity() const { return Capacity; }
|
||||
usize size() const { return length_; }
|
||||
usize capacity() const { return Capacity; }
|
||||
|
||||
const char* c_str() const { return data_; }
|
||||
const char* data() const { return data_; }
|
||||
|
||||
char& operator[](std::size_t i) { return data_[i]; }
|
||||
char& operator[](usize i) { return data_[i]; }
|
||||
|
||||
const char& operator[](std::size_t i) const { return data_[i]; }
|
||||
const char& operator[](usize i) const { return data_[i]; }
|
||||
|
||||
FixedString& operator+=(const char* str) {
|
||||
size_t len = std::strlen(str);
|
||||
usize len = std::strlen(str);
|
||||
if (length_ + len > Capacity)
|
||||
std::terminate();
|
||||
std::memcpy(data_ + length_, str, len);
|
||||
@@ -477,8 +494,8 @@ class FixedString {
|
||||
}
|
||||
|
||||
private:
|
||||
char data_[Capacity + 1]; // +1 for null terminator
|
||||
std::size_t length_;
|
||||
char data_[Capacity + 1]; // +1 for null terminator
|
||||
usize length_;
|
||||
};
|
||||
|
||||
struct CommandLine {
|
||||
@@ -554,9 +571,9 @@ void move_to_front(std::vector<T>& vec, Predicate pred) {
|
||||
|
||||
} // namespace Stockfish
|
||||
|
||||
template<std::size_t N>
|
||||
template<Stockfish::usize N>
|
||||
struct std::hash<Stockfish::FixedString<N>> {
|
||||
std::size_t operator()(const Stockfish::FixedString<N>& fstr) const noexcept {
|
||||
Stockfish::usize operator()(const Stockfish::FixedString<N>& fstr) const noexcept {
|
||||
return Stockfish::hash_bytes(fstr.data(), fstr.size());
|
||||
}
|
||||
};
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ splat_precomputed_moves(Move* moveList, Square from, Bitboard occupied, Bitboard
|
||||
static_assert(Pt != QUEEN && Pt != PAWN, "Unsupported piece type");
|
||||
|
||||
// The nth bit in the mask corresponds to the nth square in the piece's pseudo-attacks
|
||||
uint32_t mask;
|
||||
u32 mask;
|
||||
if constexpr (Pt == BISHOP || Pt == ROOK)
|
||||
{
|
||||
const Attacks::Magic& magic = Attacks::magic(from, Pt);
|
||||
|
||||
+3
-3
@@ -81,20 +81,20 @@ struct MoveSorter {
|
||||
|
||||
// Mask of all elements except the insertion point
|
||||
assert(m.value != std::numeric_limits<int>::min());
|
||||
const uint16_t expand = _kadd_mask16(_mm512_cmplt_epi32_mask(sortedValues, value), -1);
|
||||
const u16 expand = _kadd_mask16(_mm512_cmplt_epi32_mask(sortedValues, value), -1);
|
||||
|
||||
sortedValues = _mm512_mask_expand_epi32(value, expand, sortedValues);
|
||||
sortedMoves = _mm512_mask_expand_epi32(move, expand, sortedMoves);
|
||||
}
|
||||
|
||||
void write_sorted(ExtMove* moves, std::ptrdiff_t count) const {
|
||||
void write_sorted(ExtMove* moves, isize count) const {
|
||||
static_assert(sizeof(ExtMove) == 8);
|
||||
assert(count <= MAX_ELEMENTS);
|
||||
|
||||
// Because values and moves are stored separately, we need to reassemble the ExtMoves
|
||||
auto write = [&](int offset, const __m512i indices) {
|
||||
const __m512i extMoves = _mm512_permutex2var_epi32(sortedMoves, indices, sortedValues);
|
||||
const std::ptrdiff_t storeCount = count - offset;
|
||||
const isize storeCount = count - offset;
|
||||
|
||||
if (storeCount > 0)
|
||||
_mm512_mask_storeu_epi64(moves + offset, (1 << storeCount) - 1, extMoves);
|
||||
|
||||
@@ -48,7 +48,7 @@ template<PieceType PT>
|
||||
constexpr auto make_piece_indices_type() {
|
||||
static_assert(PT != PieceType::PAWN);
|
||||
|
||||
std::array<std::array<uint8_t, SQUARE_NB>, SQUARE_NB> out{};
|
||||
std::array<std::array<u8, SQUARE_NB>, SQUARE_NB> out{};
|
||||
|
||||
for (Square from = SQ_A1; from <= SQ_H8; ++from)
|
||||
{
|
||||
@@ -67,7 +67,7 @@ template<Piece P>
|
||||
constexpr auto make_piece_indices_piece() {
|
||||
static_assert(type_of(P) == PieceType::PAWN);
|
||||
|
||||
std::array<std::array<uint8_t, SQUARE_NB>, SQUARE_NB> out{};
|
||||
std::array<std::array<u8, SQUARE_NB>, SQUARE_NB> out{};
|
||||
|
||||
constexpr Color C = color_of(P);
|
||||
|
||||
@@ -91,7 +91,7 @@ constexpr auto index_lut2_array() {
|
||||
constexpr auto QUEEN_ATTACKS = make_piece_indices_type<PieceType::QUEEN>();
|
||||
constexpr auto KING_ATTACKS = make_piece_indices_type<PieceType::KING>();
|
||||
|
||||
std::array<std::array<std::array<uint8_t, SQUARE_NB>, SQUARE_NB>, PIECE_NB> indices{};
|
||||
std::array<std::array<std::array<u8, SQUARE_NB>, SQUARE_NB>, PIECE_NB> indices{};
|
||||
|
||||
indices[W_PAWN] = make_piece_indices_piece<W_PAWN>();
|
||||
indices[B_PAWN] = make_piece_indices_piece<B_PAWN>();
|
||||
@@ -155,7 +155,7 @@ constexpr auto helper_offsets = init_threat_offsets().first;
|
||||
constexpr auto offsets = init_threat_offsets().second;
|
||||
|
||||
constexpr auto init_index_luts() {
|
||||
std::array<std::array<std::array<uint32_t, 2>, PIECE_NB>, PIECE_NB> indices{};
|
||||
std::array<std::array<std::array<u32, 2>, PIECE_NB>, PIECE_NB> indices{};
|
||||
|
||||
for (Piece attacker : AllPieces)
|
||||
{
|
||||
@@ -192,13 +192,13 @@ constexpr auto index_lut2 = index_lut2_array();
|
||||
// Index of a feature for a given king position and another piece on some square
|
||||
inline sf_always_inline IndexType FullThreats::make_index(
|
||||
Color perspective, Piece attacker, Square from, Square to, Piece attacked, Square ksq) {
|
||||
const std::int8_t orientation = OrientTBL[ksq] ^ (56 * perspective);
|
||||
unsigned from_oriented = uint8_t(from) ^ orientation;
|
||||
unsigned to_oriented = uint8_t(to) ^ orientation;
|
||||
const i8 orientation = OrientTBL[ksq] ^ (56 * perspective);
|
||||
unsigned from_oriented = u8(from) ^ orientation;
|
||||
unsigned to_oriented = u8(to) ^ orientation;
|
||||
|
||||
std::int8_t swap = 8 * perspective;
|
||||
unsigned attacker_oriented = attacker ^ swap;
|
||||
unsigned attacked_oriented = attacked ^ swap;
|
||||
i8 swap = 8 * perspective;
|
||||
unsigned attacker_oriented = attacker ^ swap;
|
||||
unsigned attacked_oriented = attacked ^ swap;
|
||||
|
||||
return index_lut1[attacker_oriented][attacked_oriented][from_oriented < to_oriented]
|
||||
+ offsets[attacker_oriented][from_oriented]
|
||||
@@ -329,7 +329,7 @@ void FullThreats::append_changed_indices(Color perspective,
|
||||
}
|
||||
|
||||
bool FullThreats::requires_refresh(const DiffType& diff, Color perspective) {
|
||||
return perspective == diff.us && (int8_t(diff.ksq) & 0b100) != (int8_t(diff.prevKsq) & 0b100);
|
||||
return perspective == diff.us && (i8(diff.ksq) & 0b100) != (i8(diff.prevKsq) & 0b100);
|
||||
}
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE::Features
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#ifndef NNUE_FEATURES_FULL_THREATS_INCLUDED
|
||||
#define NNUE_FEATURES_FULL_THREATS_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../../misc.h"
|
||||
#include "../../types.h"
|
||||
@@ -39,14 +38,14 @@ class FullThreats {
|
||||
static constexpr const char* Name = "Full_Threats(Friend)";
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t HashValue = 0x8f234cb8u;
|
||||
static constexpr u32 HashValue = 0x8f234cb8u;
|
||||
|
||||
// Number of feature dimensions
|
||||
static constexpr IndexType Dimensions = 60720;
|
||||
|
||||
// clang-format off
|
||||
// Orient a square according to perspective (rotates by 180 for black)
|
||||
static constexpr std::int8_t OrientTBL[SQUARE_NB] = {
|
||||
static constexpr i8 OrientTBL[SQUARE_NB] = {
|
||||
SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1,
|
||||
SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1,
|
||||
SQ_A1, SQ_A1, SQ_A1, SQ_A1, SQ_H1, SQ_H1, SQ_H1, SQ_H1,
|
||||
|
||||
@@ -43,18 +43,18 @@ void HalfKAv2_hm::write_indices(const std::array<Piece, SQUARE_NB>& oldPieces,
|
||||
const __m512i vecOldPieces = _mm512_loadu_si512(oldPieces.data());
|
||||
const __m512i vecNewPieces = _mm512_loadu_si512(newPieces.data());
|
||||
|
||||
alignas(64) static constexpr uint16_t psiTable[COLOR_NB][16] = {
|
||||
alignas(64) static constexpr u16 psiTable[COLOR_NB][16] = {
|
||||
{PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE,
|
||||
PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_KING, PS_NONE},
|
||||
{PS_NONE, PS_B_PAWN, PS_B_KNIGHT, PS_B_BISHOP, PS_B_ROOK, PS_B_QUEEN, PS_KING, PS_NONE,
|
||||
PS_NONE, PS_W_PAWN, PS_W_KNIGHT, PS_W_BISHOP, PS_W_ROOK, PS_W_QUEEN, PS_KING, PS_NONE}};
|
||||
|
||||
const uint16_t flip = 56 * perspective;
|
||||
const __m512i orient = _mm512_set1_epi16((uint16_t) OrientTBL[ksq] ^ flip);
|
||||
const __m512i psi =
|
||||
const u16 flip = 56 * perspective;
|
||||
const __m512i orient = _mm512_set1_epi16((u16) OrientTBL[ksq] ^ flip);
|
||||
const __m512i psi =
|
||||
_mm512_castsi256_si512(_mm256_loadu_si256((const __m256i*) psiTable[perspective]));
|
||||
const __m512i psi_plus_bucket =
|
||||
_mm512_add_epi16(psi, _mm512_set1_epi16((uint16_t) KingBuckets[int(ksq) ^ flip]));
|
||||
_mm512_add_epi16(psi, _mm512_set1_epi16((u16) KingBuckets[int(ksq) ^ flip]));
|
||||
|
||||
__m512i removed_squares = _mm512_maskz_compress_epi8(removedBB, AllSquares);
|
||||
__m512i added_squares = _mm512_maskz_compress_epi8(addedBB, AllSquares);
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#ifndef NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED
|
||||
#define NNUE_FEATURES_HALF_KA_V2_HM_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "../../misc.h"
|
||||
#include "../../types.h"
|
||||
#include "../nnue_common.h"
|
||||
@@ -67,7 +65,7 @@ class HalfKAv2_hm {
|
||||
static constexpr const char* Name = "HalfKAv2_hm(Friend)";
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t HashValue = 0x7f234cb8u;
|
||||
static constexpr u32 HashValue = 0x7f234cb8u;
|
||||
|
||||
// Number of feature dimensions
|
||||
static constexpr IndexType Dimensions =
|
||||
|
||||
@@ -49,10 +49,8 @@ namespace Stockfish::Eval::NNUE::Layers {
|
||||
#ifndef ENABLE_SEQ_OPT
|
||||
|
||||
template<IndexType InputDimensions, IndexType PaddedInputDimensions, IndexType OutputDimensions>
|
||||
static void affine_transform_non_ssse3(std::int32_t* output,
|
||||
const std::int8_t* weights,
|
||||
const std::int32_t* biases,
|
||||
const std::uint8_t* input) {
|
||||
static void
|
||||
affine_transform_non_ssse3(i32* output, const i8* weights, const i32* biases, const u8* input) {
|
||||
#if defined(USE_SSE2) || defined(USE_NEON)
|
||||
#if defined(USE_SSE2)
|
||||
// At least a multiple of 16, with SSE2.
|
||||
@@ -108,14 +106,14 @@ static void affine_transform_non_ssse3(std::int32_t* output,
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
std::memcpy(output, biases, sizeof(std::int32_t) * OutputDimensions);
|
||||
std::memcpy(output, biases, sizeof(i32) * OutputDimensions);
|
||||
|
||||
// Traverse weights in transpose order to take advantage of input sparsity
|
||||
for (IndexType i = 0; i < InputDimensions; ++i)
|
||||
if (input[i])
|
||||
{
|
||||
const std::int8_t* w = &weights[i];
|
||||
const int in = input[i];
|
||||
const i8* w = &weights[i];
|
||||
const int in = input[i];
|
||||
for (IndexType j = 0; j < OutputDimensions; ++j)
|
||||
output[j] += w[j * PaddedInputDimensions] * in;
|
||||
}
|
||||
@@ -128,8 +126,8 @@ template<IndexType InDims, IndexType OutDims>
|
||||
class AffineTransform {
|
||||
public:
|
||||
// Input/output type
|
||||
using InputType = std::uint8_t;
|
||||
using OutputType = std::int32_t;
|
||||
using InputType = u8;
|
||||
using OutputType = i32;
|
||||
|
||||
// Number of input/output dimensions
|
||||
static constexpr IndexType InputDimensions = InDims;
|
||||
@@ -143,8 +141,8 @@ class AffineTransform {
|
||||
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||
std::uint32_t hashValue = 0xCC03DAE4u;
|
||||
static constexpr u32 get_hash_value(u32 prevHash) {
|
||||
u32 hashValue = 0xCC03DAE4u;
|
||||
hashValue += OutputDimensions;
|
||||
hashValue ^= prevHash >> 1;
|
||||
hashValue ^= prevHash << 31;
|
||||
@@ -183,8 +181,8 @@ class AffineTransform {
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
std::size_t get_content_hash() const {
|
||||
std::size_t h = 0;
|
||||
usize get_content_hash() const {
|
||||
usize h = 0;
|
||||
hash_combine(h, get_raw_data_hash(biases));
|
||||
hash_combine(h, get_raw_data_hash(weights));
|
||||
hash_combine(h, get_hash_value(0));
|
||||
@@ -254,11 +252,9 @@ class AffineTransform {
|
||||
#if defined(USE_VNNI)
|
||||
for (; i < NumChunks; i += 2)
|
||||
{
|
||||
const vec_t in0 =
|
||||
vec_set_32(load_as<std::int32_t>(input + i * sizeof(std::int32_t)));
|
||||
const vec_t in1 =
|
||||
vec_set_32(load_as<std::int32_t>(input + (i + 1) * sizeof(std::int32_t)));
|
||||
const auto col0 =
|
||||
const vec_t in0 = vec_set_32(load_as<i32>(input + i * sizeof(i32)));
|
||||
const vec_t in1 = vec_set_32(load_as<i32>(input + (i + 1) * sizeof(i32)));
|
||||
const auto col0 =
|
||||
reinterpret_cast<const vec_t*>(&weights[i * OutputDimensions * 4]);
|
||||
const auto col1 =
|
||||
reinterpret_cast<const vec_t*>(&weights[(i + 1) * OutputDimensions * 4]);
|
||||
@@ -275,9 +271,8 @@ class AffineTransform {
|
||||
#endif
|
||||
for (; i < NumChunks; ++i)
|
||||
{
|
||||
const vec_t in0 =
|
||||
vec_set_32(load_as<std::int32_t>(input + i * sizeof(std::int32_t)));
|
||||
const auto col0 =
|
||||
const vec_t in0 = vec_set_32(load_as<i32>(input + i * sizeof(i32)));
|
||||
const auto col0 =
|
||||
reinterpret_cast<const vec_t*>(&weights[i * OutputDimensions * 4]);
|
||||
|
||||
for (IndexType k = 0; k < NumRegs; ++k)
|
||||
@@ -354,7 +349,7 @@ class AffineTransform {
|
||||
|
||||
private:
|
||||
using BiasType = OutputType;
|
||||
using WeightType = std::int8_t;
|
||||
using WeightType = i8;
|
||||
|
||||
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
||||
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
||||
|
||||
@@ -44,8 +44,8 @@ template<IndexType InDims, IndexType OutDims>
|
||||
class AffineTransformSparseInput {
|
||||
public:
|
||||
// Input/output type
|
||||
using InputType = std::uint8_t;
|
||||
using OutputType = std::int32_t;
|
||||
using InputType = u8;
|
||||
using OutputType = i32;
|
||||
|
||||
// Number of input/output dimensions
|
||||
static constexpr IndexType InputDimensions = InDims;
|
||||
@@ -68,8 +68,8 @@ class AffineTransformSparseInput {
|
||||
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||
std::uint32_t hashValue = 0xCC03DAE4u;
|
||||
static constexpr u32 get_hash_value(u32 prevHash) {
|
||||
u32 hashValue = 0xCC03DAE4u;
|
||||
hashValue += OutputDimensions;
|
||||
hashValue ^= prevHash >> 1;
|
||||
hashValue ^= prevHash << 31;
|
||||
@@ -108,8 +108,8 @@ class AffineTransformSparseInput {
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
std::size_t get_content_hash() const {
|
||||
std::size_t h = 0;
|
||||
usize get_content_hash() const {
|
||||
usize h = 0;
|
||||
hash_combine(h, get_raw_data_hash(biases));
|
||||
hash_combine(h, get_raw_data_hash(weights));
|
||||
hash_combine(h, get_hash_value(0));
|
||||
@@ -179,7 +179,7 @@ class AffineTransformSparseInput {
|
||||
acc[k] = biasvec[k];
|
||||
|
||||
// convince GCC to not do weird pointer arithmetic in the following loops
|
||||
const std::int8_t* weights_cp = weights;
|
||||
const i8* weights_cp = weights;
|
||||
|
||||
#if defined(USE_AVX512)
|
||||
const auto* start = nnzInfo.nnz;
|
||||
@@ -190,16 +190,13 @@ class AffineTransformSparseInput {
|
||||
#if defined(USE_VNNI)
|
||||
while (start < end - 2)
|
||||
{
|
||||
const std::ptrdiff_t i0 = *start++;
|
||||
const std::ptrdiff_t i1 = *start++;
|
||||
const std::ptrdiff_t i2 = *start++;
|
||||
const invec_t in0 =
|
||||
vec_set_32(load_as<std::int32_t>(input + i0 * sizeof(std::int32_t)));
|
||||
const invec_t in1 =
|
||||
vec_set_32(load_as<std::int32_t>(input + i1 * sizeof(std::int32_t)));
|
||||
const invec_t in2 =
|
||||
vec_set_32(load_as<std::int32_t>(input + i2 * sizeof(std::int32_t)));
|
||||
const auto col0 =
|
||||
const isize i0 = *start++;
|
||||
const isize i1 = *start++;
|
||||
const isize i2 = *start++;
|
||||
const invec_t in0 = vec_set_32(load_as<i32>(input + i0 * sizeof(i32)));
|
||||
const invec_t in1 = vec_set_32(load_as<i32>(input + i1 * sizeof(i32)));
|
||||
const invec_t in2 = vec_set_32(load_as<i32>(input + i2 * sizeof(i32)));
|
||||
const auto col0 =
|
||||
reinterpret_cast<const invec_t*>(&weights_cp[i0 * OutputDimensions * ChunkSize]);
|
||||
const auto col1 =
|
||||
reinterpret_cast<const invec_t*>(&weights_cp[i1 * OutputDimensions * ChunkSize]);
|
||||
@@ -219,8 +216,8 @@ class AffineTransformSparseInput {
|
||||
|
||||
while (start < end)
|
||||
{
|
||||
const std::ptrdiff_t i = *start++;
|
||||
const invec_t in = vec_set_32(load_as<std::int32_t>(input + i * sizeof(std::int32_t)));
|
||||
const isize i = *start++;
|
||||
const invec_t in = vec_set_32(load_as<i32>(input + i * sizeof(i32)));
|
||||
const auto col =
|
||||
reinterpret_cast<const invec_t*>(&weights_cp[i * OutputDimensions * ChunkSize]);
|
||||
for (IndexType k = 0; k < NumAccums; ++k)
|
||||
@@ -231,10 +228,10 @@ class AffineTransformSparseInput {
|
||||
|
||||
for (IndexType k = 0; k < InputDimensions / 256; ++k)
|
||||
{
|
||||
uint64_t bits = load_as<uint64_t>(nnzInfo.bitset + k * 8);
|
||||
ptrdiff_t base = k * 64;
|
||||
u64 bits = load_as<u64>(nnzInfo.bitset + k * 8);
|
||||
isize base = k * 64;
|
||||
|
||||
auto* base_addr = input + base * sizeof(std::int32_t);
|
||||
auto* base_addr = input + base * sizeof(i32);
|
||||
auto* weights_base = &weights_cp[base * OutputDimensions * ChunkSize];
|
||||
|
||||
#if defined(USE_NEON_DOTPROD) && defined(__GNUC__) && !defined(__clang__)
|
||||
@@ -253,8 +250,8 @@ class AffineTransformSparseInput {
|
||||
|
||||
while (bits)
|
||||
{
|
||||
ptrdiff_t i = pop_lsb(bits);
|
||||
const auto* input_addr = base_addr + i * sizeof(std::int32_t);
|
||||
isize i = pop_lsb(bits);
|
||||
const auto* input_addr = base_addr + i * sizeof(i32);
|
||||
auto col =
|
||||
reinterpret_cast<const invec_t*>(&weights_base[i * OutputDimensions * ChunkSize]);
|
||||
|
||||
@@ -263,7 +260,7 @@ class AffineTransformSparseInput {
|
||||
#undef FIX_GCC15_MISOPTIMIZATION
|
||||
#endif
|
||||
|
||||
const invec_t in = vec_set_32(load_as<std::int32_t>(input_addr));
|
||||
const invec_t in = vec_set_32(load_as<i32>(input_addr));
|
||||
for (IndexType l = 0; l < NumAccums; ++l)
|
||||
vec_add_dpbusd_32(acc[l], in, col[l]);
|
||||
}
|
||||
@@ -287,7 +284,7 @@ class AffineTransformSparseInput {
|
||||
|
||||
private:
|
||||
using BiasType = OutputType;
|
||||
using WeightType = std::int8_t;
|
||||
using WeightType = i8;
|
||||
|
||||
alignas(CacheLineSize) BiasType biases[OutputDimensions];
|
||||
alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions];
|
||||
|
||||
@@ -34,8 +34,8 @@ template<IndexType InDims, int WeightScaleBitsLocal = WeightScaleBits>
|
||||
class ClippedReLU {
|
||||
public:
|
||||
// Input/output type
|
||||
using InputType = std::int32_t;
|
||||
using OutputType = std::uint8_t;
|
||||
using InputType = i32;
|
||||
using OutputType = u8;
|
||||
|
||||
// Number of input/output dimensions
|
||||
static constexpr IndexType InputDimensions = InDims;
|
||||
@@ -46,8 +46,8 @@ class ClippedReLU {
|
||||
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||
std::uint32_t hashValue = 0x538D24C7u;
|
||||
static constexpr u32 get_hash_value(u32 prevHash) {
|
||||
u32 hashValue = 0x538D24C7u;
|
||||
hashValue += prevHash;
|
||||
// TODO: consider including WeightScaleBitsLocal in the hash value.
|
||||
// For now omitted on purpose because not written by trainer (yet)
|
||||
@@ -60,8 +60,8 @@ class ClippedReLU {
|
||||
// Write network parameters
|
||||
bool write_parameters(std::ostream&) const { return true; }
|
||||
|
||||
std::size_t get_content_hash() const {
|
||||
std::size_t h = 0;
|
||||
usize get_content_hash() const {
|
||||
usize h = 0;
|
||||
hash_combine(h, get_hash_value(0));
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,8 @@ template<IndexType InDims, int WeightScaleBitsLocal = WeightScaleBits>
|
||||
class SqrClippedReLU {
|
||||
public:
|
||||
// Input/output type
|
||||
using InputType = std::int32_t;
|
||||
using OutputType = std::uint8_t;
|
||||
using InputType = i32;
|
||||
using OutputType = u8;
|
||||
|
||||
// Number of input/output dimensions
|
||||
static constexpr IndexType InputDimensions = InDims;
|
||||
@@ -47,8 +47,8 @@ class SqrClippedReLU {
|
||||
using OutputBuffer = OutputType[PaddedOutputDimensions];
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) {
|
||||
std::uint32_t hashValue = 0x538D24C7u;
|
||||
static constexpr u32 get_hash_value(u32 prevHash) {
|
||||
u32 hashValue = 0x538D24C7u;
|
||||
hashValue += prevHash;
|
||||
// TODO: consider including WeightScaleBitsLocal in the hash value.
|
||||
// For now omitted on purpose because not written by trainer (yet)
|
||||
@@ -61,8 +61,8 @@ class SqrClippedReLU {
|
||||
// Write network parameters
|
||||
bool write_parameters(std::ostream&) const { return true; }
|
||||
|
||||
std::size_t get_content_hash() const {
|
||||
std::size_t h = 0;
|
||||
usize get_content_hash() const {
|
||||
usize h = 0;
|
||||
hash_combine(h, get_hash_value(0));
|
||||
return h;
|
||||
}
|
||||
|
||||
+22
-24
@@ -67,8 +67,8 @@ namespace Detail {
|
||||
template<typename T>
|
||||
bool read_parameters(std::istream& stream, T& reference) {
|
||||
|
||||
std::uint32_t header;
|
||||
header = read_little_endian<std::uint32_t>(stream);
|
||||
u32 header;
|
||||
header = read_little_endian<u32>(stream);
|
||||
if (!stream || header != T::get_hash_value())
|
||||
return false;
|
||||
return reference.read_parameters(stream);
|
||||
@@ -78,7 +78,7 @@ bool read_parameters(std::istream& stream, T& reference) {
|
||||
template<typename T>
|
||||
bool write_parameters(std::ostream& stream, const T& reference) {
|
||||
|
||||
write_little_endian<std::uint32_t>(stream, T::get_hash_value());
|
||||
write_little_endian<u32>(stream, T::get_hash_value());
|
||||
return reference.write_parameters(stream);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ NetworkOutput Network::evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches& cache) const {
|
||||
|
||||
constexpr uint64_t alignment = CacheLineSize;
|
||||
constexpr u64 alignment = CacheLineSize;
|
||||
|
||||
alignas(alignment) TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
||||
|
||||
@@ -188,7 +188,7 @@ void Network::verify(std::string evalfilePath,
|
||||
|
||||
if (f)
|
||||
{
|
||||
size_t size = sizeof(featureTransformer) + sizeof(NetworkArchitecture) * LayerStacks;
|
||||
usize size = sizeof(featureTransformer) + sizeof(NetworkArchitecture) * LayerStacks;
|
||||
f("NNUE evaluation using " + evalfilePath + " (" + std::to_string(size / (1024 * 1024))
|
||||
+ "MiB, (" + std::to_string(featureTransformer.InputDimensions) + ", "
|
||||
+ std::to_string(network[0].TransformedFeatureDimensions) + ", "
|
||||
@@ -202,7 +202,7 @@ NnueEvalTrace Network::trace_evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches& cache) const {
|
||||
|
||||
constexpr uint64_t alignment = CacheLineSize;
|
||||
constexpr u64 alignment = CacheLineSize;
|
||||
|
||||
alignas(alignment) TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize];
|
||||
|
||||
@@ -241,7 +241,7 @@ void Network::load_internal() {
|
||||
// C++ way to prepare a buffer for a memory stream
|
||||
class MemoryBuffer: public std::basic_streambuf<char> {
|
||||
public:
|
||||
MemoryBuffer(char* p, size_t n) {
|
||||
MemoryBuffer(char* p, usize n) {
|
||||
setg(p, p, p + n);
|
||||
setp(p, p + n);
|
||||
}
|
||||
@@ -253,7 +253,7 @@ void Network::load_internal() {
|
||||
#endif
|
||||
|
||||
MemoryBuffer buffer(const_cast<char*>(reinterpret_cast<const char*>(gEmbeddedNNUEData)),
|
||||
size_t(gEmbeddedNNUESize));
|
||||
usize(gEmbeddedNNUESize));
|
||||
|
||||
std::istream stream(&buffer);
|
||||
auto description = load(stream);
|
||||
@@ -287,11 +287,11 @@ std::optional<std::string> Network::load(std::istream& stream) {
|
||||
}
|
||||
|
||||
|
||||
std::size_t Network::get_content_hash() const {
|
||||
usize Network::get_content_hash() const {
|
||||
if (!initialized)
|
||||
return 0;
|
||||
|
||||
std::size_t h = 0;
|
||||
usize h = 0;
|
||||
hash_combine(h, featureTransformer);
|
||||
for (auto&& layerstack : network)
|
||||
hash_combine(h, layerstack);
|
||||
@@ -300,12 +300,12 @@ std::size_t Network::get_content_hash() const {
|
||||
}
|
||||
|
||||
// Read network header
|
||||
bool Network::read_header(std::istream& stream, std::uint32_t* hashValue, std::string* desc) const {
|
||||
std::uint32_t version, size;
|
||||
bool Network::read_header(std::istream& stream, u32* hashValue, std::string* desc) const {
|
||||
u32 version, size;
|
||||
|
||||
version = read_little_endian<std::uint32_t>(stream);
|
||||
*hashValue = read_little_endian<std::uint32_t>(stream);
|
||||
size = read_little_endian<std::uint32_t>(stream);
|
||||
version = read_little_endian<u32>(stream);
|
||||
*hashValue = read_little_endian<u32>(stream);
|
||||
size = read_little_endian<u32>(stream);
|
||||
if (!stream || version != Version)
|
||||
return false;
|
||||
desc->resize(size);
|
||||
@@ -315,26 +315,24 @@ bool Network::read_header(std::istream& stream, std::uint32_t* hashValue, std::s
|
||||
|
||||
|
||||
// Write network header
|
||||
bool Network::write_header(std::ostream& stream,
|
||||
std::uint32_t hashValue,
|
||||
const std::string& desc) const {
|
||||
write_little_endian<std::uint32_t>(stream, Version);
|
||||
write_little_endian<std::uint32_t>(stream, hashValue);
|
||||
write_little_endian<std::uint32_t>(stream, std::uint32_t(desc.size()));
|
||||
bool Network::write_header(std::ostream& stream, u32 hashValue, const std::string& desc) const {
|
||||
write_little_endian<u32>(stream, Version);
|
||||
write_little_endian<u32>(stream, hashValue);
|
||||
write_little_endian<u32>(stream, u32(desc.size()));
|
||||
stream.write(&desc[0], desc.size());
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
|
||||
bool Network::read_parameters(std::istream& stream, std::string& netDescription) {
|
||||
std::uint32_t hashValue;
|
||||
u32 hashValue;
|
||||
if (!read_header(stream, &hashValue, &netDescription))
|
||||
return false;
|
||||
if (hashValue != Network::hash)
|
||||
return false;
|
||||
if (!Detail::read_parameters(stream, featureTransformer))
|
||||
return false;
|
||||
for (std::size_t i = 0; i < LayerStacks; ++i)
|
||||
for (usize i = 0; i < LayerStacks; ++i)
|
||||
{
|
||||
if (!Detail::read_parameters(stream, network[i]))
|
||||
return false;
|
||||
@@ -348,7 +346,7 @@ bool Network::write_parameters(std::ostream& stream, const std::string& netDescr
|
||||
return false;
|
||||
if (!Detail::write_parameters(stream, featureTransformer))
|
||||
return false;
|
||||
for (std::size_t i = 0; i < LayerStacks; ++i)
|
||||
for (usize i = 0; i < LayerStacks; ++i)
|
||||
{
|
||||
if (!Detail::write_parameters(stream, network[i]))
|
||||
return false;
|
||||
|
||||
+6
-7
@@ -19,8 +19,6 @@
|
||||
#ifndef NETWORK_H_INCLUDED
|
||||
#define NETWORK_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -30,6 +28,7 @@
|
||||
#include <tuple>
|
||||
|
||||
#include "../types.h"
|
||||
#include "../misc.h"
|
||||
#include "nnue_architecture.h"
|
||||
#include "nnue_feature_transformer.h"
|
||||
#include "nnue_misc.h"
|
||||
@@ -62,7 +61,7 @@ class Network {
|
||||
void load(const std::string& rootDirectory, std::string evalfilePath);
|
||||
bool save(const std::optional<std::string>& filename) const;
|
||||
|
||||
std::size_t get_content_hash() const;
|
||||
usize get_content_hash() const;
|
||||
|
||||
NetworkOutput evaluate(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
@@ -83,8 +82,8 @@ class Network {
|
||||
bool save(std::ostream&, const std::string&, const std::string&) const;
|
||||
std::optional<std::string> load(std::istream&);
|
||||
|
||||
bool read_header(std::istream&, std::uint32_t*, std::string*) const;
|
||||
bool write_header(std::ostream&, std::uint32_t, const std::string&) const;
|
||||
bool read_header(std::istream&, u32*, std::string*) const;
|
||||
bool write_header(std::ostream&, u32, const std::string&) const;
|
||||
|
||||
bool read_parameters(std::istream&, std::string&);
|
||||
bool write_parameters(std::ostream&, const std::string&) const;
|
||||
@@ -100,7 +99,7 @@ class Network {
|
||||
bool initialized = false;
|
||||
|
||||
// Hash value of evaluation function structure
|
||||
static constexpr std::uint32_t hash =
|
||||
static constexpr u32 hash =
|
||||
FeatureTransformer::get_hash_value() ^ NetworkArchitecture::get_hash_value();
|
||||
|
||||
friend struct AccumulatorCaches;
|
||||
@@ -111,7 +110,7 @@ class Network {
|
||||
|
||||
template<>
|
||||
struct std::hash<Stockfish::Eval::NNUE::Network> {
|
||||
std::size_t operator()(const Stockfish::Eval::NNUE::Network& network) const noexcept {
|
||||
Stockfish::usize operator()(const Stockfish::Eval::NNUE::Network& network) const noexcept {
|
||||
return network.get_content_hash();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "nnue_accumulator.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -157,9 +156,9 @@ void AccumulatorStack::evaluate_side(Color perspective,
|
||||
// Find the earliest usable accumulator, this can either be a computed accumulator or the accumulator
|
||||
// state just before a change that requires full refresh.
|
||||
template<typename FeatureSet>
|
||||
std::size_t AccumulatorStack::find_last_usable_accumulator(Color perspective) const noexcept {
|
||||
usize AccumulatorStack::find_last_usable_accumulator(Color perspective) const noexcept {
|
||||
|
||||
for (std::size_t curr_idx = size - 1; curr_idx > 0; curr_idx--)
|
||||
for (usize curr_idx = size - 1; curr_idx > 0; curr_idx--)
|
||||
{
|
||||
if (accumulators<FeatureSet>()[curr_idx].computed[perspective])
|
||||
return curr_idx;
|
||||
@@ -175,14 +174,14 @@ template<typename FeatureSet>
|
||||
void AccumulatorStack::forward_update_incremental(Color perspective,
|
||||
const Position& pos,
|
||||
const FeatureTransformer& featureTransformer,
|
||||
const std::size_t begin) noexcept {
|
||||
const usize begin) noexcept {
|
||||
|
||||
assert(begin < accumulators<FeatureSet>().size());
|
||||
assert(accumulators<FeatureSet>()[begin].computed[perspective]);
|
||||
|
||||
const Square ksq = pos.square<KING>(perspective);
|
||||
|
||||
for (std::size_t next = begin + 1; next < size; next++)
|
||||
for (usize next = begin + 1; next < size; next++)
|
||||
{
|
||||
update_accumulator_incremental<true>(perspective, featureTransformer, ksq,
|
||||
mut_accumulators<FeatureSet>()[next],
|
||||
@@ -197,7 +196,7 @@ void AccumulatorStack::backward_update_incremental(Color perspective,
|
||||
|
||||
const Position& pos,
|
||||
const FeatureTransformer& featureTransformer,
|
||||
const std::size_t end) noexcept {
|
||||
const usize end) noexcept {
|
||||
|
||||
assert(end < accumulators<FeatureSet>().size());
|
||||
assert(end < size);
|
||||
@@ -205,7 +204,7 @@ void AccumulatorStack::backward_update_incremental(Color perspective,
|
||||
|
||||
const Square ksq = pos.square<KING>(perspective);
|
||||
|
||||
for (std::int64_t next = std::int64_t(size) - 2; next >= std::int64_t(end); next--)
|
||||
for (i64 next = i64(size) - 2; next >= i64(end); next--)
|
||||
update_accumulator_incremental<false>(perspective, featureTransformer, ksq,
|
||||
mut_accumulators<FeatureSet>()[next],
|
||||
accumulators<FeatureSet>()[next + 1]);
|
||||
@@ -299,9 +298,9 @@ struct AccumulatorUpdateContext {
|
||||
|
||||
for (int i = 0; i < removed.ssize(); ++i)
|
||||
{
|
||||
size_t index = removed[i];
|
||||
const size_t offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_i8_t*>(&threatWeights[offset]);
|
||||
usize index = removed[i];
|
||||
const usize offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_i8_t*>(&threatWeights[offset]);
|
||||
|
||||
#ifdef USE_NEON
|
||||
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
||||
@@ -317,9 +316,9 @@ struct AccumulatorUpdateContext {
|
||||
|
||||
for (int i = 0; i < added.ssize(); ++i)
|
||||
{
|
||||
size_t index = added[i];
|
||||
const size_t offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_i8_t*>(&threatWeights[offset]);
|
||||
usize index = added[i];
|
||||
const usize offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_i8_t*>(&threatWeights[offset]);
|
||||
|
||||
#ifdef USE_NEON
|
||||
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
||||
@@ -351,23 +350,23 @@ struct AccumulatorUpdateContext {
|
||||
|
||||
for (int i = 0; i < removed.ssize(); ++i)
|
||||
{
|
||||
size_t index = removed[i];
|
||||
const size_t offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||
usize index = removed[i];
|
||||
const usize offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||
&featureTransformer.threatPsqtWeights[offset]);
|
||||
|
||||
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < added.ssize(); ++i)
|
||||
{
|
||||
size_t index = added[i];
|
||||
const size_t offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||
usize index = added[i];
|
||||
const usize offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt = reinterpret_cast<const psqt_vec_t*>(
|
||||
&featureTransformer.threatPsqtWeights[offset]);
|
||||
|
||||
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
||||
}
|
||||
|
||||
@@ -387,7 +386,7 @@ struct AccumulatorUpdateContext {
|
||||
for (IndexType j = 0; j < Dimensions; ++j)
|
||||
toAcc[j] -= featureTransformer.threatWeights[offset + j];
|
||||
|
||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||
toPsqtAcc[k] -= featureTransformer.threatPsqtWeights[index * PSQTBuckets + k];
|
||||
}
|
||||
|
||||
@@ -398,7 +397,7 @@ struct AccumulatorUpdateContext {
|
||||
for (IndexType j = 0; j < Dimensions; ++j)
|
||||
toAcc[j] += featureTransformer.threatWeights[offset + j];
|
||||
|
||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||
toPsqtAcc[k] += featureTransformer.threatPsqtWeights[index * PSQTBuckets + k];
|
||||
}
|
||||
|
||||
@@ -511,8 +510,8 @@ Bitboard get_changed_pieces(const std::array<Piece, SQUARE_NB>& oldPieces,
|
||||
{
|
||||
const __m256i old_v = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(&oldPieces[i]));
|
||||
const __m256i new_v = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(&newPieces[i]));
|
||||
const __m256i cmpEqual = _mm256_cmpeq_epi8(old_v, new_v);
|
||||
const std::uint32_t equalMask = _mm256_movemask_epi8(cmpEqual);
|
||||
const __m256i cmpEqual = _mm256_cmpeq_epi8(old_v, new_v);
|
||||
const u32 equalMask = _mm256_movemask_epi8(cmpEqual);
|
||||
sameBB |= static_cast<Bitboard>(equalMask) << i;
|
||||
}
|
||||
return ~sameBB;
|
||||
@@ -551,8 +550,8 @@ Bitboard get_changed_pieces(const std::array<Piece, SQUARE_NB>& oldPieces,
|
||||
|
||||
return changed;
|
||||
#elif defined(USE_NEON)
|
||||
uint8x16x4_t old_v = vld4q_u8(reinterpret_cast<const uint8_t*>(oldPieces.data()));
|
||||
uint8x16x4_t new_v = vld4q_u8(reinterpret_cast<const uint8_t*>(newPieces.data()));
|
||||
uint8x16x4_t old_v = vld4q_u8(reinterpret_cast<const u8*>(oldPieces.data()));
|
||||
uint8x16x4_t new_v = vld4q_u8(reinterpret_cast<const u8*>(newPieces.data()));
|
||||
auto cmp = [=](const int i) { return vceqq_u8(old_v.val[i], new_v.val[i]); };
|
||||
|
||||
uint8x16_t cmp0_1 = vsriq_n_u8(cmp(1), cmp(0), 1);
|
||||
@@ -627,18 +626,18 @@ void update_accumulator_refresh_cache(Color perspecti
|
||||
|
||||
for (int i = 0; i < removed.ssize(); ++i)
|
||||
{
|
||||
size_t index = removed[i];
|
||||
const size_t offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_t*>(&weights[offset]);
|
||||
usize index = removed[i];
|
||||
const usize offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_t*>(&weights[offset]);
|
||||
|
||||
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
|
||||
acc[k] = vec_sub_16(acc[k], column[k]);
|
||||
}
|
||||
for (int i = 0; i < added.ssize(); ++i)
|
||||
{
|
||||
size_t index = added[i];
|
||||
const size_t offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_t*>(&weights[offset]);
|
||||
usize index = added[i];
|
||||
const usize offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_t*>(&weights[offset]);
|
||||
|
||||
for (IndexType k = 0; k < Tiling::NumRegs; ++k)
|
||||
acc[k] = vec_add_16(acc[k], column[k]);
|
||||
@@ -664,22 +663,22 @@ void update_accumulator_refresh_cache(Color perspecti
|
||||
|
||||
for (int i = 0; i < removed.ssize(); ++i)
|
||||
{
|
||||
size_t index = removed[i];
|
||||
const size_t offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt =
|
||||
usize index = removed[i];
|
||||
const usize offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt =
|
||||
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offset]);
|
||||
|
||||
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
psqt[k] = vec_sub_psqt_32(psqt[k], columnPsqt[k]);
|
||||
}
|
||||
for (int i = 0; i < added.ssize(); ++i)
|
||||
{
|
||||
size_t index = added[i];
|
||||
const size_t offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt =
|
||||
usize index = added[i];
|
||||
const usize offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt =
|
||||
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.psqtWeights[offset]);
|
||||
|
||||
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
||||
}
|
||||
|
||||
@@ -697,7 +696,7 @@ void update_accumulator_refresh_cache(Color perspecti
|
||||
for (IndexType j = 0; j < Dimensions; ++j)
|
||||
entry.accumulation[j] -= featureTransformer.weights[offset + j];
|
||||
|
||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||
entry.psqtAccumulation[k] -= featureTransformer.psqtWeights[index * PSQTBuckets + k];
|
||||
}
|
||||
for (const auto index : added)
|
||||
@@ -706,7 +705,7 @@ void update_accumulator_refresh_cache(Color perspecti
|
||||
for (IndexType j = 0; j < Dimensions; ++j)
|
||||
entry.accumulation[j] += featureTransformer.weights[offset + j];
|
||||
|
||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||
entry.psqtAccumulation[k] += featureTransformer.psqtWeights[index * PSQTBuckets + k];
|
||||
}
|
||||
|
||||
@@ -747,9 +746,9 @@ void update_threats_accumulator_full(Color perspec
|
||||
|
||||
for (; i < active.ssize(); ++i)
|
||||
{
|
||||
size_t index = active[i];
|
||||
const size_t offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_i8_t*>(&threatWeights[offset]);
|
||||
usize index = active[i];
|
||||
const usize offset = Dimensions * index;
|
||||
auto* column = reinterpret_cast<const vec_i8_t*>(&threatWeights[offset]);
|
||||
|
||||
#ifdef USE_NEON
|
||||
for (IndexType k = 0; k < Tiling::NumRegs; k += 2)
|
||||
@@ -779,12 +778,12 @@ void update_threats_accumulator_full(Color perspec
|
||||
|
||||
for (int i = 0; i < active.ssize(); ++i)
|
||||
{
|
||||
size_t index = active[i];
|
||||
const size_t offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt =
|
||||
usize index = active[i];
|
||||
const usize offset = PSQTBuckets * index + j * Tiling::PsqtTileHeight;
|
||||
auto* columnPsqt =
|
||||
reinterpret_cast<const psqt_vec_t*>(&featureTransformer.threatPsqtWeights[offset]);
|
||||
|
||||
for (std::size_t k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
for (usize k = 0; k < Tiling::NumPsqtRegs; ++k)
|
||||
psqt[k] = vec_add_psqt_32(psqt[k], columnPsqt[k]);
|
||||
}
|
||||
|
||||
@@ -797,7 +796,7 @@ void update_threats_accumulator_full(Color perspec
|
||||
for (IndexType j = 0; j < Dimensions; ++j)
|
||||
accumulator.accumulation[perspective][j] = 0;
|
||||
|
||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||
accumulator.psqtAccumulation[perspective][k] = 0;
|
||||
|
||||
for (const auto index : active)
|
||||
@@ -808,7 +807,7 @@ void update_threats_accumulator_full(Color perspec
|
||||
accumulator.accumulation[perspective][j] +=
|
||||
featureTransformer.threatWeights[offset + j];
|
||||
|
||||
for (std::size_t k = 0; k < PSQTBuckets; ++k)
|
||||
for (usize k = 0; k < PSQTBuckets; ++k)
|
||||
accumulator.psqtAccumulation[perspective][k] +=
|
||||
featureTransformer.threatPsqtWeights[index * PSQTBuckets + k];
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "../types.h"
|
||||
#include "../misc.h"
|
||||
#include "nnue_architecture.h"
|
||||
#include "nnue_common.h"
|
||||
|
||||
@@ -43,9 +43,9 @@ class FeatureTransformer;
|
||||
|
||||
// Class that holds the result of affine transformation of input features
|
||||
struct alignas(CacheLineSize) Accumulator {
|
||||
std::array<std::array<std::int16_t, L1>, COLOR_NB> accumulation;
|
||||
std::array<std::array<std::int32_t, PSQTBuckets>, COLOR_NB> psqtAccumulation;
|
||||
std::array<bool, COLOR_NB> computed = {};
|
||||
std::array<std::array<i16, L1>, COLOR_NB> accumulation;
|
||||
std::array<std::array<i32, PSQTBuckets>, COLOR_NB> psqtAccumulation;
|
||||
std::array<bool, COLOR_NB> computed = {};
|
||||
};
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ struct AccumulatorState: public Accumulator {
|
||||
|
||||
class AccumulatorStack {
|
||||
public:
|
||||
static constexpr std::size_t MaxSize = MAX_PLY + 1;
|
||||
static constexpr usize MaxSize = MAX_PLY + 1;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] const AccumulatorState<T>& latest() const noexcept;
|
||||
@@ -138,23 +138,23 @@ class AccumulatorStack {
|
||||
[[maybe_unused]] AccumulatorCaches& cache) noexcept;
|
||||
|
||||
template<typename FeatureSet>
|
||||
[[nodiscard]] std::size_t find_last_usable_accumulator(Color perspective) const noexcept;
|
||||
[[nodiscard]] usize find_last_usable_accumulator(Color perspective) const noexcept;
|
||||
|
||||
template<typename FeatureSet>
|
||||
void forward_update_incremental(Color perspective,
|
||||
const Position& pos,
|
||||
const FeatureTransformer& featureTransformer,
|
||||
const std::size_t begin) noexcept;
|
||||
const usize begin) noexcept;
|
||||
|
||||
template<typename FeatureSet>
|
||||
void backward_update_incremental(Color perspective,
|
||||
const Position& pos,
|
||||
const FeatureTransformer& featureTransformer,
|
||||
const std::size_t end) noexcept;
|
||||
const usize end) noexcept;
|
||||
|
||||
std::array<AccumulatorState<PSQFeatureSet>, MaxSize> psq_accumulators;
|
||||
std::array<AccumulatorState<ThreatFeatureSet>, MaxSize> threat_accumulators;
|
||||
std::size_t size = 1;
|
||||
usize size = 1;
|
||||
};
|
||||
|
||||
} // namespace Stockfish::Eval::NNUE
|
||||
|
||||
@@ -67,9 +67,9 @@ struct NetworkArchitecture {
|
||||
Layers::AffineTransform<FC_1_OUTPUTS, 1> fc_2;
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t get_hash_value() {
|
||||
static constexpr u32 get_hash_value() {
|
||||
// input slice hash
|
||||
std::uint32_t hashValue = 0xEC42E90Du;
|
||||
u32 hashValue = 0xEC42E90Du;
|
||||
hashValue ^= TransformedFeatureDimensions * 2;
|
||||
|
||||
hashValue = decltype(fc_0)::get_hash_value(hashValue);
|
||||
@@ -97,8 +97,8 @@ struct NetworkArchitecture {
|
||||
&& fc_2.write_parameters(stream);
|
||||
}
|
||||
|
||||
std::int32_t propagate(const TransformedFeatureType* transformedFeatures,
|
||||
const NNZInfo<L1>& nnzInfo) const {
|
||||
i32 propagate(const TransformedFeatureType* transformedFeatures,
|
||||
const NNZInfo<L1>& nnzInfo) const {
|
||||
struct alignas(CacheLineSize) Buffer {
|
||||
alignas(CacheLineSize) typename decltype(fc_0)::OutputBuffer fc_0_out;
|
||||
alignas(CacheLineSize) typename decltype(ac_sqr_0)::OutputType
|
||||
@@ -126,21 +126,20 @@ struct NetworkArchitecture {
|
||||
// for int8 activations and weights this is (L1 + L3) * 16129 making
|
||||
// fwdOut safe from overflow until (L1 + L3) > 133,144
|
||||
// first layer and last layer use WeightScaleBits + 1
|
||||
std::int32_t fwdOut = buffer.fc_2_out[0] + buffer.fc_0_out[FC_0_OUTPUTS];
|
||||
i32 fwdOut = buffer.fc_2_out[0] + buffer.fc_0_out[FC_0_OUTPUTS];
|
||||
// fwdOut is such that 1.0 is equal to HiddenOneVal*(1<<WeightScaleBits)*2 in
|
||||
// quantized form, but we want 1.0 to be equal to 600*OutputScale
|
||||
// to make overflow impossible we cast to int64_t
|
||||
constexpr std::int64_t multiplier = 600 * OutputScale;
|
||||
constexpr std::int64_t denominator = static_cast<std::int64_t>(HiddenOneVal)
|
||||
* static_cast<std::int64_t>(1U << WeightScaleBits) * 2;
|
||||
// to make overflow impossible we cast to i64
|
||||
constexpr i64 multiplier = 600 * OutputScale;
|
||||
constexpr i64 denominator =
|
||||
static_cast<i64>(HiddenOneVal) * static_cast<i64>(1U << WeightScaleBits) * 2;
|
||||
|
||||
std::int32_t outputValue =
|
||||
static_cast<std::int32_t>((static_cast<std::int64_t>(fwdOut) * multiplier) / denominator);
|
||||
i32 outputValue = static_cast<i32>((static_cast<i64>(fwdOut) * multiplier) / denominator);
|
||||
return outputValue;
|
||||
}
|
||||
|
||||
std::size_t get_content_hash() const {
|
||||
std::size_t h = 0;
|
||||
usize get_content_hash() const {
|
||||
usize h = 0;
|
||||
hash_combine(h, fc_0.get_content_hash());
|
||||
hash_combine(h, ac_sqr_0.get_content_hash());
|
||||
hash_combine(h, ac_0.get_content_hash());
|
||||
@@ -156,7 +155,8 @@ struct NetworkArchitecture {
|
||||
|
||||
template<>
|
||||
struct std::hash<Stockfish::Eval::NNUE::NetworkArchitecture> {
|
||||
std::size_t operator()(const Stockfish::Eval::NNUE::NetworkArchitecture& arch) const noexcept {
|
||||
Stockfish::usize
|
||||
operator()(const Stockfish::Eval::NNUE::NetworkArchitecture& arch) const noexcept {
|
||||
return arch.get_content_hash();
|
||||
}
|
||||
};
|
||||
|
||||
+46
-46
@@ -55,14 +55,14 @@
|
||||
|
||||
namespace Stockfish::Eval::NNUE {
|
||||
|
||||
using BiasType = std::int16_t;
|
||||
using ThreatWeightType = std::int8_t;
|
||||
using WeightType = std::int16_t;
|
||||
using PSQTWeightType = std::int32_t;
|
||||
using IndexType = std::uint32_t;
|
||||
using BiasType = i16;
|
||||
using ThreatWeightType = i8;
|
||||
using WeightType = i16;
|
||||
using PSQTWeightType = i32;
|
||||
using IndexType = u32;
|
||||
|
||||
// Version of the evaluation file
|
||||
constexpr std::uint32_t Version = 0x6A448AFAu;
|
||||
constexpr u32 Version = 0x6A448AFAu;
|
||||
|
||||
// Constant used in evaluation value calculation
|
||||
constexpr int OutputScale = 16;
|
||||
@@ -73,32 +73,32 @@ constexpr int HiddenOneVal = 128;
|
||||
constexpr int HiddenMaxVal = 127;
|
||||
|
||||
// Size of cache line (in bytes)
|
||||
constexpr std::size_t CacheLineSize = 64;
|
||||
constexpr usize CacheLineSize = 64;
|
||||
|
||||
constexpr const char Leb128MagicString[] = "COMPRESSED_LEB128";
|
||||
constexpr const std::size_t Leb128MagicStringSize = sizeof(Leb128MagicString) - 1;
|
||||
constexpr const char Leb128MagicString[] = "COMPRESSED_LEB128";
|
||||
constexpr const usize Leb128MagicStringSize = sizeof(Leb128MagicString) - 1;
|
||||
|
||||
// SIMD width (in bytes)
|
||||
#if defined(USE_AVX2)
|
||||
constexpr std::size_t SimdWidth = 32;
|
||||
constexpr usize SimdWidth = 32;
|
||||
|
||||
#elif defined(USE_LASX)
|
||||
constexpr std::size_t SimdWidth = 32;
|
||||
constexpr usize SimdWidth = 32;
|
||||
|
||||
#elif defined(USE_SSE2)
|
||||
constexpr std::size_t SimdWidth = 16;
|
||||
constexpr usize SimdWidth = 16;
|
||||
|
||||
#elif defined(USE_NEON)
|
||||
constexpr std::size_t SimdWidth = 16;
|
||||
constexpr usize SimdWidth = 16;
|
||||
|
||||
#elif defined(USE_LSX)
|
||||
constexpr std::size_t SimdWidth = 16;
|
||||
constexpr usize SimdWidth = 16;
|
||||
#endif
|
||||
|
||||
constexpr std::size_t MaxSimdWidth = 32;
|
||||
constexpr usize MaxSimdWidth = 32;
|
||||
|
||||
// Type of input feature after conversion
|
||||
using TransformedFeatureType = std::uint8_t;
|
||||
using TransformedFeatureType = u8;
|
||||
|
||||
// Round n up to be a multiple of base
|
||||
template<typename IntType>
|
||||
@@ -118,11 +118,11 @@ inline IntType read_little_endian(std::istream& stream) {
|
||||
stream.read(reinterpret_cast<char*>(&result), sizeof(IntType));
|
||||
else
|
||||
{
|
||||
std::uint8_t u[sizeof(IntType)];
|
||||
u8 u[sizeof(IntType)];
|
||||
std::make_unsigned_t<IntType> v = 0;
|
||||
|
||||
stream.read(reinterpret_cast<char*>(u), sizeof(IntType));
|
||||
for (std::size_t i = 0; i < sizeof(IntType); ++i)
|
||||
for (usize i = 0; i < sizeof(IntType); ++i)
|
||||
v = (v << 8) | u[sizeof(IntType) - i - 1];
|
||||
|
||||
std::memcpy(&result, &v, sizeof(IntType));
|
||||
@@ -143,20 +143,20 @@ inline void write_little_endian(std::ostream& stream, IntType value) {
|
||||
stream.write(reinterpret_cast<const char*>(&value), sizeof(IntType));
|
||||
else
|
||||
{
|
||||
std::uint8_t u[sizeof(IntType)];
|
||||
u8 u[sizeof(IntType)];
|
||||
std::make_unsigned_t<IntType> v = value;
|
||||
|
||||
std::size_t i = 0;
|
||||
usize i = 0;
|
||||
// if constexpr to silence the warning about shift by 8
|
||||
if constexpr (sizeof(IntType) > 1)
|
||||
{
|
||||
for (; i + 1 < sizeof(IntType); ++i)
|
||||
{
|
||||
u[i] = std::uint8_t(v);
|
||||
u[i] = u8(v);
|
||||
v >>= 8;
|
||||
}
|
||||
}
|
||||
u[i] = std::uint8_t(v);
|
||||
u[i] = u8(v);
|
||||
|
||||
stream.write(reinterpret_cast<char*>(u), sizeof(IntType));
|
||||
}
|
||||
@@ -166,11 +166,11 @@ inline void write_little_endian(std::ostream& stream, IntType value) {
|
||||
// Read integers in bulk from a little-endian stream.
|
||||
// This reads N integers from stream s and puts them in array out.
|
||||
template<typename IntType>
|
||||
inline void read_little_endian(std::istream& stream, IntType* out, std::size_t count) {
|
||||
inline void read_little_endian(std::istream& stream, IntType* out, usize count) {
|
||||
if (IsLittleEndian)
|
||||
stream.read(reinterpret_cast<char*>(out), sizeof(IntType) * count);
|
||||
else
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
for (usize i = 0; i < count; ++i)
|
||||
out[i] = read_little_endian<IntType>(stream);
|
||||
}
|
||||
|
||||
@@ -178,39 +178,39 @@ inline void read_little_endian(std::istream& stream, IntType* out, std::size_t c
|
||||
// Write integers in bulk to a little-endian stream.
|
||||
// This takes N integers from array values and writes them on stream s.
|
||||
template<typename IntType>
|
||||
inline void write_little_endian(std::ostream& stream, const IntType* values, std::size_t count) {
|
||||
inline void write_little_endian(std::ostream& stream, const IntType* values, usize count) {
|
||||
if (IsLittleEndian)
|
||||
stream.write(reinterpret_cast<const char*>(values), sizeof(IntType) * count);
|
||||
else
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
for (usize i = 0; i < count; ++i)
|
||||
write_little_endian<IntType>(stream, values[i]);
|
||||
}
|
||||
|
||||
// Read N signed integers from the stream s, putting them in the array out.
|
||||
// The stream is assumed to be compressed using the signed LEB128 format.
|
||||
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
||||
template<typename BufType, typename IntType, std::size_t Count>
|
||||
template<typename BufType, typename IntType, usize Count>
|
||||
inline void read_leb_128_detail(std::istream& stream,
|
||||
std::array<IntType, Count>& out,
|
||||
std::uint32_t& bytes_left,
|
||||
u32& bytes_left,
|
||||
BufType& buf,
|
||||
std::uint32_t& buf_pos) {
|
||||
u32& buf_pos) {
|
||||
|
||||
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
|
||||
static_assert(sizeof(IntType) <= 4, "Not implemented for types larger than 32 bit");
|
||||
|
||||
IntType result = 0;
|
||||
size_t shift = 0, i = 0;
|
||||
usize shift = 0, i = 0;
|
||||
while (i < Count)
|
||||
{
|
||||
if (buf_pos == buf.size())
|
||||
{
|
||||
stream.read(reinterpret_cast<char*>(buf.data()),
|
||||
std::min(std::size_t(bytes_left), buf.size()));
|
||||
std::min(usize(bytes_left), buf.size()));
|
||||
buf_pos = 0;
|
||||
}
|
||||
|
||||
std::uint8_t byte = buf[buf_pos++];
|
||||
u8 byte = buf[buf_pos++];
|
||||
--bytes_left;
|
||||
result |= (byte & 0x7f) << (shift % 32);
|
||||
shift += 7;
|
||||
@@ -231,9 +231,9 @@ inline void read_leb_128(std::istream& stream, Arrays&... outs) {
|
||||
stream.read(leb128MagicString, Leb128MagicStringSize);
|
||||
assert(strncmp(Leb128MagicString, leb128MagicString, Leb128MagicStringSize) == 0);
|
||||
|
||||
auto bytes_left = read_little_endian<std::uint32_t>(stream);
|
||||
std::array<std::uint8_t, 8192> buf;
|
||||
std::uint32_t buf_pos = std::uint32_t(buf.size());
|
||||
auto bytes_left = read_little_endian<u32>(stream);
|
||||
std::array<u8, 8192> buf;
|
||||
u32 buf_pos = u32(buf.size());
|
||||
|
||||
(read_leb_128_detail(stream, outs, bytes_left, buf, buf_pos), ...);
|
||||
|
||||
@@ -245,7 +245,7 @@ inline void read_leb_128(std::istream& stream, Arrays&... outs) {
|
||||
// This takes N integers from array values, compresses them with
|
||||
// the LEB128 algorithm and writes the result on the stream s.
|
||||
// See https://en.wikipedia.org/wiki/LEB128 for a description of the compression scheme.
|
||||
template<typename IntType, std::size_t Count>
|
||||
template<typename IntType, usize Count>
|
||||
inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>& values) {
|
||||
|
||||
// Write our LEB128 magic string
|
||||
@@ -253,11 +253,11 @@ inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>
|
||||
|
||||
static_assert(std::is_signed_v<IntType>, "Not implemented for unsigned types");
|
||||
|
||||
std::uint32_t byte_count = 0;
|
||||
for (std::size_t i = 0; i < Count; ++i)
|
||||
u32 byte_count = 0;
|
||||
for (usize i = 0; i < Count; ++i)
|
||||
{
|
||||
IntType value = values[i];
|
||||
std::uint8_t byte;
|
||||
IntType value = values[i];
|
||||
u8 byte;
|
||||
do
|
||||
{
|
||||
byte = value & 0x7f;
|
||||
@@ -268,9 +268,9 @@ inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>
|
||||
|
||||
write_little_endian(stream, byte_count);
|
||||
|
||||
const std::uint32_t BUF_SIZE = 4096;
|
||||
std::uint8_t buf[BUF_SIZE];
|
||||
std::uint32_t buf_pos = 0;
|
||||
const u32 BUF_SIZE = 4096;
|
||||
u8 buf[BUF_SIZE];
|
||||
u32 buf_pos = 0;
|
||||
|
||||
auto flush = [&]() {
|
||||
if (buf_pos > 0)
|
||||
@@ -280,18 +280,18 @@ inline void write_leb_128(std::ostream& stream, const std::array<IntType, Count>
|
||||
}
|
||||
};
|
||||
|
||||
auto write = [&](std::uint8_t b) {
|
||||
auto write = [&](u8 b) {
|
||||
buf[buf_pos++] = b;
|
||||
if (buf_pos == BUF_SIZE)
|
||||
flush();
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < Count; ++i)
|
||||
for (usize i = 0; i < Count; ++i)
|
||||
{
|
||||
IntType value = values[i];
|
||||
while (true)
|
||||
{
|
||||
std::uint8_t byte = value & 0x7f;
|
||||
u8 byte = value & 0x7f;
|
||||
value >>= 7;
|
||||
if ((byte & 0x40) == 0 ? value == 0 : value == -1)
|
||||
{
|
||||
|
||||
@@ -37,35 +37,34 @@
|
||||
namespace Stockfish::Eval::NNUE {
|
||||
|
||||
// Returns the inverse of a permutation
|
||||
template<std::size_t Len>
|
||||
constexpr std::array<std::size_t, Len>
|
||||
invert_permutation(const std::array<std::size_t, Len>& order) {
|
||||
std::array<std::size_t, Len> inverse{};
|
||||
for (std::size_t i = 0; i < order.size(); i++)
|
||||
template<usize Len>
|
||||
constexpr std::array<usize, Len> invert_permutation(const std::array<usize, Len>& order) {
|
||||
std::array<usize, Len> inverse{};
|
||||
for (usize i = 0; i < order.size(); i++)
|
||||
inverse[order[i]] = i;
|
||||
return inverse;
|
||||
}
|
||||
|
||||
// Divide a byte region of size TotalSize to chunks of size
|
||||
// BlockSize, and permute the blocks by a given order
|
||||
template<std::size_t BlockSize, typename T, std::size_t N, std::size_t OrderSize>
|
||||
void permute(std::array<T, N>& data, const std::array<std::size_t, OrderSize>& order) {
|
||||
constexpr std::size_t TotalSize = N * sizeof(T);
|
||||
template<usize BlockSize, typename T, usize N, usize OrderSize>
|
||||
void permute(std::array<T, N>& data, const std::array<usize, OrderSize>& order) {
|
||||
constexpr usize TotalSize = N * sizeof(T);
|
||||
|
||||
static_assert(TotalSize % (BlockSize * OrderSize) == 0,
|
||||
"ChunkSize * OrderSize must perfectly divide TotalSize");
|
||||
|
||||
constexpr std::size_t ProcessChunkSize = BlockSize * OrderSize;
|
||||
constexpr usize ProcessChunkSize = BlockSize * OrderSize;
|
||||
|
||||
std::array<std::byte, ProcessChunkSize> buffer{};
|
||||
|
||||
std::byte* const bytes = reinterpret_cast<std::byte*>(data.data());
|
||||
|
||||
for (std::size_t i = 0; i < TotalSize; i += ProcessChunkSize)
|
||||
for (usize i = 0; i < TotalSize; i += ProcessChunkSize)
|
||||
{
|
||||
std::byte* const values = &bytes[i];
|
||||
|
||||
for (std::size_t j = 0; j < OrderSize; j++)
|
||||
for (usize j = 0; j < OrderSize; j++)
|
||||
{
|
||||
auto* const buffer_chunk = &buffer[j * BlockSize];
|
||||
auto* const value_chunk = &values[order[j] * BlockSize];
|
||||
@@ -92,12 +91,12 @@ class FeatureTransformer {
|
||||
static constexpr IndexType OutputDimensions = HalfDimensions;
|
||||
|
||||
// Size of forward propagation buffer
|
||||
static constexpr std::size_t BufferSize = OutputDimensions * sizeof(OutputType);
|
||||
static constexpr usize BufferSize = OutputDimensions * sizeof(OutputType);
|
||||
|
||||
// Store the order by which 128-bit blocks of a 1024-bit data must
|
||||
// be permuted so that calling packus on adjacent vectors of 16-bit
|
||||
// integers loaded from the data results in the pre-permutation order
|
||||
static constexpr auto PackusEpi16Order = []() -> std::array<std::size_t, 8> {
|
||||
static constexpr auto PackusEpi16Order = []() -> std::array<usize, 8> {
|
||||
#if defined(USE_AVX512)
|
||||
// _mm512_packus_epi16 after permutation:
|
||||
// | 0 | 2 | 4 | 6 | // Vector 0
|
||||
@@ -117,8 +116,8 @@ class FeatureTransformer {
|
||||
|
||||
static constexpr auto InversePackusEpi16Order = invert_permutation(PackusEpi16Order);
|
||||
|
||||
static constexpr std::uint32_t combine_hash(std::initializer_list<std::uint32_t> hashes) {
|
||||
std::uint32_t hash = 0;
|
||||
static constexpr u32 combine_hash(std::initializer_list<u32> hashes) {
|
||||
u32 hash = 0;
|
||||
for (const auto component_hash : hashes)
|
||||
{
|
||||
hash = (hash << 1) | (hash >> 31);
|
||||
@@ -128,7 +127,7 @@ class FeatureTransformer {
|
||||
}
|
||||
|
||||
// Hash value embedded in the evaluation file
|
||||
static constexpr std::uint32_t get_hash_value() {
|
||||
static constexpr u32 get_hash_value() {
|
||||
return combine_hash({ThreatFeatureSet::HashValue, PSQFeatureSet::HashValue})
|
||||
^ (OutputDimensions * 2);
|
||||
}
|
||||
@@ -181,8 +180,8 @@ class FeatureTransformer {
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
std::size_t get_content_hash() const {
|
||||
std::size_t h = 0;
|
||||
usize get_content_hash() const {
|
||||
usize h = 0;
|
||||
|
||||
hash_combine(h, get_raw_data_hash(biases));
|
||||
hash_combine(h, get_raw_data_hash(weights));
|
||||
@@ -197,12 +196,12 @@ class FeatureTransformer {
|
||||
}
|
||||
|
||||
// Convert input features
|
||||
std::int32_t transform(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches& cache,
|
||||
OutputType* output,
|
||||
int bucket,
|
||||
NNZInfo<OutputDimensions>& nnzInfo) const {
|
||||
i32 transform(const Position& pos,
|
||||
AccumulatorStack& accumulatorStack,
|
||||
AccumulatorCaches& cache,
|
||||
OutputType* output,
|
||||
int bucket,
|
||||
NNZInfo<OutputDimensions>& nnzInfo) const {
|
||||
|
||||
using namespace SIMD;
|
||||
accumulatorStack.evaluate(pos, *this, cache);
|
||||
@@ -381,7 +380,8 @@ class FeatureTransformer {
|
||||
|
||||
template<>
|
||||
struct std::hash<Stockfish::Eval::NNUE::FeatureTransformer> {
|
||||
std::size_t operator()(const Stockfish::Eval::NNUE::FeatureTransformer& ft) const noexcept {
|
||||
Stockfish::usize
|
||||
operator()(const Stockfish::Eval::NNUE::FeatureTransformer& ft) const noexcept {
|
||||
return ft.get_content_hash();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "../position.h"
|
||||
#include "../misc.h"
|
||||
#include "../types.h"
|
||||
#include "../uci.h"
|
||||
#include "network.h"
|
||||
@@ -71,7 +72,7 @@ trace(Position& pos, const Eval::NNUE::Network& network, Eval::NNUE::Accumulator
|
||||
<< "| | (PSQT) | (Layers) | |\n"
|
||||
<< "+------------+------------+------------+------------+\n";
|
||||
|
||||
for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket)
|
||||
for (usize bucket = 0; bucket < LayerStacks; ++bucket)
|
||||
{
|
||||
ss << "| " << bucket << " " //
|
||||
<< " | ";
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#ifndef NNUE_MISC_H_INCLUDED
|
||||
#define NNUE_MISC_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -47,9 +46,9 @@ struct EvalFile {
|
||||
struct NnueEvalTrace {
|
||||
static_assert(LayerStacks == PSQTBuckets);
|
||||
|
||||
Value psqt[LayerStacks];
|
||||
Value positional[LayerStacks];
|
||||
std::size_t correctBucket;
|
||||
Value psqt[LayerStacks];
|
||||
Value positional[LayerStacks];
|
||||
usize correctBucket;
|
||||
};
|
||||
|
||||
class Network;
|
||||
@@ -62,8 +61,8 @@ std::string trace(Position& pos, const Network& network, AccumulatorCaches& cach
|
||||
|
||||
template<>
|
||||
struct std::hash<Stockfish::Eval::NNUE::EvalFile> {
|
||||
std::size_t operator()(const Stockfish::Eval::NNUE::EvalFile& evalFile) const noexcept {
|
||||
std::size_t h = 0;
|
||||
Stockfish::usize operator()(const Stockfish::Eval::NNUE::EvalFile& evalFile) const noexcept {
|
||||
Stockfish::usize h = 0;
|
||||
Stockfish::hash_combine(h, evalFile.defaultName);
|
||||
Stockfish::hash_combine(h, evalFile.current);
|
||||
Stockfish::hash_combine(h, evalFile.netDescription);
|
||||
|
||||
@@ -32,27 +32,27 @@ struct NNZInfo {
|
||||
#if defined(USE_AVX512)
|
||||
unsigned count = 0;
|
||||
// indices of non-zero chunks
|
||||
uint16_t nnz[Dimensions / 4];
|
||||
u16 nnz[Dimensions / 4];
|
||||
|
||||
#ifdef USE_AVX512ICL
|
||||
alignas(64) static constexpr auto Indices = []() {
|
||||
std::array<std::array<uint16_t, 32>, 2> indices{};
|
||||
std::array<std::array<u16, 32>, 2> indices{};
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
indices[i] = {0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23,
|
||||
8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31};
|
||||
for (uint16_t& m : indices[i])
|
||||
for (u16& m : indices[i])
|
||||
m += i * Dimensions / 8;
|
||||
}
|
||||
return indices;
|
||||
}();
|
||||
#else
|
||||
alignas(64) static constexpr auto Indices = []() {
|
||||
std::array<std::array<uint32_t, 16>, 2> indices{};
|
||||
std::array<std::array<u32, 16>, 2> indices{};
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
indices[i] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
|
||||
for (uint32_t& m : indices[i])
|
||||
for (u32& m : indices[i])
|
||||
m += i * Dimensions / 8;
|
||||
}
|
||||
return indices;
|
||||
@@ -105,10 +105,10 @@ struct NNZInfo {
|
||||
NNZCursor make_cursor(bool perspective) { return {*this, perspective, count}; }
|
||||
#else
|
||||
// Each 8-bit chunk
|
||||
uint8_t bitset[(Dimensions + 31) / 32];
|
||||
u8 bitset[(Dimensions + 31) / 32];
|
||||
|
||||
struct NNZCursor {
|
||||
uint8_t* out;
|
||||
u8* out;
|
||||
|
||||
NNZCursor(NNZInfo& info, bool perspective) {
|
||||
out = info.bitset + perspective * Dimensions / 64;
|
||||
@@ -119,7 +119,7 @@ struct NNZInfo {
|
||||
using namespace SIMD;
|
||||
|
||||
#ifdef USE_NEON
|
||||
alignas(16) static constexpr uint16_t Mask8[8] = {1, 16, 2, 32, 4, 64, 8, 128};
|
||||
alignas(16) static constexpr u16 Mask8[8] = {1, 16, 2, 32, 4, 64, 8, 128};
|
||||
|
||||
uint32x4_t n1 = vreinterpretq_u32_s16(neurons1);
|
||||
uint32x4_t n2 = vreinterpretq_u32_s16(neurons2);
|
||||
|
||||
+14
-14
@@ -135,7 +135,7 @@ using vec_uint_t = __m256i;
|
||||
|
||||
#elif USE_SSE2
|
||||
using vec_t = __m128i;
|
||||
using vec_i8_t = std::uint64_t; // for the correct size -- will be loaded into an xmm reg
|
||||
using vec_i8_t = u64; // for the correct size -- will be loaded into an xmm reg
|
||||
using vec128_t = __m128i;
|
||||
using psqt_vec_t = __m128i;
|
||||
using vec_uint_t = __m128i;
|
||||
@@ -162,17 +162,17 @@ using vec_uint_t = __m128i;
|
||||
#endif
|
||||
|
||||
#ifdef __i386__
|
||||
inline __m128i _mm_cvtsi64_si128(int64_t val) {
|
||||
inline __m128i _mm_cvtsi64_si128(i64 val) {
|
||||
return _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&val));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_SSE41
|
||||
#define vec_convert_8_16(a) _mm_cvtepi8_epi16(_mm_cvtsi64_si128(static_cast<int64_t>(a)))
|
||||
#define vec_convert_8_16(a) _mm_cvtepi8_epi16(_mm_cvtsi64_si128(static_cast<i64>(a)))
|
||||
#else
|
||||
// Credit: Yoshie2000
|
||||
inline __m128i vec_convert_8_16(uint64_t x) {
|
||||
__m128i v8 = _mm_cvtsi64_si128(static_cast<int64_t>(x));
|
||||
inline __m128i vec_convert_8_16(u64 x) {
|
||||
__m128i v8 = _mm_cvtsi64_si128(static_cast<i64>(x));
|
||||
__m128i sign = _mm_cmpgt_epi8(_mm_setzero_si128(), v8);
|
||||
return _mm_unpacklo_epi8(v8, sign);
|
||||
}
|
||||
@@ -216,13 +216,13 @@ using vec_uint_t __attribute__((may_alias)) = uint32x4_t;
|
||||
#define vec_sub_psqt_32(a, b) vsubq_s32(a, b)
|
||||
#define vec_zero_psqt() psqt_vec_t{0}
|
||||
|
||||
static constexpr std::uint32_t Mask[4] = {1, 2, 4, 8};
|
||||
static constexpr u32 Mask[4] = {1, 2, 4, 8};
|
||||
#define vec_nnz(a) \
|
||||
vaddvq_u32(vandq_u32(vtstq_u32((uint32x4_t) a, (uint32x4_t) a), vld1q_u32(Mask)))
|
||||
#define vec128_zero vdupq_n_u16(0)
|
||||
#define vec128_set_16(a) vdupq_n_u16(a)
|
||||
#define vec128_load(a) vld1q_u16(reinterpret_cast<const std::uint16_t*>(a))
|
||||
#define vec128_storeu(a, b) vst1q_u16(reinterpret_cast<std::uint16_t*>(a), b)
|
||||
#define vec128_load(a) vld1q_u16(reinterpret_cast<const u16*>(a))
|
||||
#define vec128_storeu(a, b) vst1q_u16(reinterpret_cast<u16*>(a), b)
|
||||
#define vec128_add(a, b) vaddq_u16(a, b)
|
||||
|
||||
#define NumRegistersSIMD 16
|
||||
@@ -302,8 +302,8 @@ inline __m256i lasx_cvtepi8_epi16(__m128i a) {
|
||||
__asm__("vext2xv.h.b %u0, %u1" : "=f"(out) : "f"(a));
|
||||
return out;
|
||||
#else
|
||||
int64_t lo = (int64_t) __lsx_vpickve2gr_d(a, 0);
|
||||
int64_t hi = (int64_t) __lsx_vpickve2gr_d(a, 1);
|
||||
i64 lo = (i64) __lsx_vpickve2gr_d(a, 0);
|
||||
i64 hi = (i64) __lsx_vpickve2gr_d(a, 1);
|
||||
__m256i v = __lasx_xvldi(0);
|
||||
v = __lasx_xvinsgr2vr_d(v, lo, 0);
|
||||
v = __lasx_xvinsgr2vr_d(v, hi, 2);
|
||||
@@ -319,7 +319,7 @@ inline int lasx_vec_nnz(__m256i a) {
|
||||
|
||||
#elif USE_LSX
|
||||
using vec_t = __m128i;
|
||||
using vec_i8_t = std::uint64_t;
|
||||
using vec_i8_t = u64;
|
||||
using vec128_t = __m128i;
|
||||
using psqt_vec_t = __m128i;
|
||||
using vec_uint_t = __m128i;
|
||||
@@ -365,7 +365,7 @@ inline int lsx_vec_nnz(__m128i a) {
|
||||
}
|
||||
#define vec_nnz(a) lsx_vec_nnz(a)
|
||||
|
||||
inline __m128i vec_convert_8_16(std::uint64_t x) {
|
||||
inline __m128i vec_convert_8_16(u64 x) {
|
||||
__m128i v = __lsx_vldrepl_d(reinterpret_cast<const void*>(&x), 0);
|
||||
return __lsx_vsllwil_h_b(v, 0);
|
||||
}
|
||||
@@ -589,8 +589,8 @@ class SIMDTiling {
|
||||
|
||||
template<typename SIMDRegisterType, typename LaneType, int NumLanes, int MaxRegisters>
|
||||
static constexpr int BestRegisterCount() {
|
||||
constexpr std::size_t RegisterSize = sizeof(SIMDRegisterType);
|
||||
constexpr std::size_t LaneSize = sizeof(LaneType);
|
||||
constexpr usize RegisterSize = sizeof(SIMDRegisterType);
|
||||
constexpr usize LaneSize = sizeof(LaneType);
|
||||
|
||||
static_assert(RegisterSize >= LaneSize);
|
||||
static_assert(MaxRegisters <= NumRegistersSIMD);
|
||||
|
||||
+44
-43
@@ -37,6 +37,7 @@
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "misc.h"
|
||||
#include "shm.h"
|
||||
|
||||
// We support linux very well, but we explicitly do NOT support Android,
|
||||
@@ -53,10 +54,6 @@
|
||||
#define _WIN32_WINNT 0x0601 // Force to include needed API prototypes
|
||||
#endif
|
||||
|
||||
// On Windows each processor group can have up to 64 processors.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups
|
||||
static constexpr size_t WIN_PROCESSOR_GROUP_SIZE = 64;
|
||||
|
||||
#if !defined(NOMINMAX)
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
@@ -77,8 +74,8 @@ using GetThreadSelectedCpuSetMasks_t = BOOL (*)(HANDLE, PGROUP_AFFINITY, USHORT,
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
using CpuIndex = size_t;
|
||||
using NumaIndex = size_t;
|
||||
using CpuIndex = usize;
|
||||
using NumaIndex = usize;
|
||||
|
||||
inline CpuIndex get_hardware_concurrency() {
|
||||
CpuIndex concurrency = std::thread::hardware_concurrency();
|
||||
@@ -97,6 +94,10 @@ inline const CpuIndex SYSTEM_THREADS_NB = std::max<CpuIndex>(1, get_hardware_con
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
// On Windows each processor group can have up to 64 processors.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups
|
||||
static constexpr usize WIN_PROCESSOR_GROUP_SIZE = 64;
|
||||
|
||||
struct WindowsAffinity {
|
||||
std::optional<std::set<CpuIndex>> oldApi;
|
||||
std::optional<std::set<CpuIndex>> newApi;
|
||||
@@ -134,7 +135,7 @@ inline std::pair<BOOL, std::vector<USHORT>> get_process_group_affinity() {
|
||||
|
||||
// GetProcessGroupAffinity requires the GroupArray argument to be
|
||||
// aligned to 4 bytes instead of just 2.
|
||||
static constexpr size_t GroupArrayMinimumAlignment = 4;
|
||||
static constexpr usize GroupArrayMinimumAlignment = 4;
|
||||
static_assert(GroupArrayMinimumAlignment >= alignof(USHORT));
|
||||
|
||||
// The function should succeed the second time, but it may fail if the group
|
||||
@@ -217,9 +218,9 @@ inline WindowsAffinity get_process_affinity() {
|
||||
|
||||
for (USHORT i = 0; i < RequiredMaskCount; ++i)
|
||||
{
|
||||
const size_t procGroupIndex = groupAffinities[i].Group;
|
||||
const usize procGroupIndex = groupAffinities[i].Group;
|
||||
|
||||
for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j)
|
||||
for (usize j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j)
|
||||
{
|
||||
if (groupAffinities[i].Mask & (KAFFINITY(1) << j))
|
||||
cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j);
|
||||
@@ -271,10 +272,10 @@ inline WindowsAffinity get_process_affinity() {
|
||||
{
|
||||
std::set<CpuIndex> cpus;
|
||||
|
||||
const size_t procGroupIndex = groupAffinity[0];
|
||||
const usize procGroupIndex = groupAffinity[0];
|
||||
|
||||
const uint64_t mask = static_cast<uint64_t>(proc);
|
||||
for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j)
|
||||
const u64 mask = static_cast<u64>(proc);
|
||||
for (usize j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j)
|
||||
{
|
||||
if (mask & (KAFFINITY(1) << j))
|
||||
cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j);
|
||||
@@ -312,8 +313,8 @@ inline WindowsAffinity get_process_affinity() {
|
||||
// choice could influence the resulting affinity.
|
||||
// We assume the processor IDs within the group are
|
||||
// filled sequentially from 0.
|
||||
uint64_t procCombined = std::numeric_limits<uint64_t>::max();
|
||||
uint64_t sysCombined = std::numeric_limits<uint64_t>::max();
|
||||
u64 procCombined = std::numeric_limits<u64>::max();
|
||||
u64 sysCombined = std::numeric_limits<u64>::max();
|
||||
|
||||
for (int i = 0; i < std::min(numActiveProcessors, 2); ++i)
|
||||
{
|
||||
@@ -341,14 +342,14 @@ inline WindowsAffinity get_process_affinity() {
|
||||
return;
|
||||
}
|
||||
|
||||
procCombined &= static_cast<uint64_t>(proc2);
|
||||
sysCombined &= static_cast<uint64_t>(sys2);
|
||||
procCombined &= static_cast<u64>(proc2);
|
||||
sysCombined &= static_cast<u64>(sys2);
|
||||
}
|
||||
|
||||
if (procCombined != sysCombined)
|
||||
isAffinityFull = false;
|
||||
|
||||
for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j)
|
||||
for (usize j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j)
|
||||
{
|
||||
if (procCombined & (KAFFINITY(1) << j))
|
||||
cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j);
|
||||
@@ -439,7 +440,7 @@ inline std::set<CpuIndex> get_process_affinity() {
|
||||
if (mask == nullptr)
|
||||
std::exit(EXIT_FAILURE);
|
||||
|
||||
const size_t masksize = CPU_ALLOC_SIZE(MaxNumCpus);
|
||||
const usize masksize = CPU_ALLOC_SIZE(MaxNumCpus);
|
||||
|
||||
CPU_ZERO_S(masksize, mask);
|
||||
|
||||
@@ -502,7 +503,7 @@ struct SystemNumaPolicy {};
|
||||
struct L3DomainsPolicy {};
|
||||
// Group system-reported L3 domains until they reach bundleSize
|
||||
struct BundledL3Policy {
|
||||
size_t bundleSize;
|
||||
usize bundleSize;
|
||||
};
|
||||
|
||||
using NumaAutoPolicy = std::variant<SystemNumaPolicy, L3DomainsPolicy, BundledL3Policy>;
|
||||
@@ -581,7 +582,7 @@ class NumaConfig {
|
||||
bool l3Success = false;
|
||||
if (!std::holds_alternative<SystemNumaPolicy>(policy))
|
||||
{
|
||||
size_t l3BundleSize = 0;
|
||||
usize l3BundleSize = 0;
|
||||
if (const auto* v = std::get_if<BundledL3Policy>(&policy))
|
||||
{
|
||||
l3BundleSize = v->bundleSize;
|
||||
@@ -627,10 +628,10 @@ class NumaConfig {
|
||||
if (cpus.empty())
|
||||
continue;
|
||||
|
||||
size_t lastProcGroupIndex = *(cpus.begin()) / WIN_PROCESSOR_GROUP_SIZE;
|
||||
usize lastProcGroupIndex = *(cpus.begin()) / WIN_PROCESSOR_GROUP_SIZE;
|
||||
for (CpuIndex c : cpus)
|
||||
{
|
||||
const size_t procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE;
|
||||
const usize procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE;
|
||||
if (procGroupIndex != lastProcGroupIndex)
|
||||
{
|
||||
splitNodeIndex += 1;
|
||||
@@ -769,7 +770,7 @@ class NumaConfig {
|
||||
if (numThreads <= 1)
|
||||
return false;
|
||||
|
||||
size_t largestNodeSize = 0;
|
||||
usize largestNodeSize = 0;
|
||||
for (auto&& cpus : nodes)
|
||||
if (cpus.size() > largestNodeSize)
|
||||
largestNodeSize = cpus.size();
|
||||
@@ -780,7 +781,7 @@ class NumaConfig {
|
||||
<= SmallNodeThreshold;
|
||||
};
|
||||
|
||||
size_t numNotSmallNodes = 0;
|
||||
usize numNotSmallNodes = 0;
|
||||
for (auto&& cpus : nodes)
|
||||
if (!is_node_small(cpus))
|
||||
numNotSmallNodes += 1;
|
||||
@@ -800,7 +801,7 @@ class NumaConfig {
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<size_t> occupation(nodes.size(), 0);
|
||||
std::vector<usize> occupation(nodes.size(), 0);
|
||||
for (CpuIndex c = 0; c < numThreads; ++c)
|
||||
{
|
||||
NumaIndex bestNode{0};
|
||||
@@ -838,7 +839,7 @@ class NumaConfig {
|
||||
if (mask == nullptr)
|
||||
std::exit(EXIT_FAILURE);
|
||||
|
||||
const size_t masksize = CPU_ALLOC_SIZE(highestCpuIndex + 1);
|
||||
const usize masksize = CPU_ALLOC_SIZE(highestCpuIndex + 1);
|
||||
|
||||
CPU_ZERO_S(masksize, mask);
|
||||
|
||||
@@ -880,8 +881,8 @@ class NumaConfig {
|
||||
|
||||
for (CpuIndex c : nodes[n])
|
||||
{
|
||||
const size_t procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE;
|
||||
const size_t idxWithinProcGroup = c % WIN_PROCESSOR_GROUP_SIZE;
|
||||
const usize procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE;
|
||||
const usize idxWithinProcGroup = c % WIN_PROCESSOR_GROUP_SIZE;
|
||||
groupAffinities[procGroupIndex].Mask |= KAFFINITY(1) << idxWithinProcGroup;
|
||||
}
|
||||
|
||||
@@ -919,12 +920,12 @@ class NumaConfig {
|
||||
GROUP_AFFINITY affinity;
|
||||
std::memset(&affinity, 0, sizeof(GROUP_AFFINITY));
|
||||
// We use an ordered set to be sure to get the smallest cpu number here.
|
||||
const size_t forcedProcGroupIndex = *(nodes[n].begin()) / WIN_PROCESSOR_GROUP_SIZE;
|
||||
affinity.Group = static_cast<WORD>(forcedProcGroupIndex);
|
||||
const usize forcedProcGroupIndex = *(nodes[n].begin()) / WIN_PROCESSOR_GROUP_SIZE;
|
||||
affinity.Group = static_cast<WORD>(forcedProcGroupIndex);
|
||||
for (CpuIndex c : nodes[n])
|
||||
{
|
||||
const size_t procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE;
|
||||
const size_t idxWithinProcGroup = c % WIN_PROCESSOR_GROUP_SIZE;
|
||||
const usize procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE;
|
||||
const usize idxWithinProcGroup = c % WIN_PROCESSOR_GROUP_SIZE;
|
||||
// We skip processors that are not in the same processor group.
|
||||
// If everything was set up correctly this will never be an issue,
|
||||
// but we have to account for bad NUMA node specification.
|
||||
@@ -1026,8 +1027,8 @@ class NumaConfig {
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<size_t> indices_from_shortened_string(const std::string& s) {
|
||||
std::vector<size_t> indices;
|
||||
static std::vector<usize> indices_from_shortened_string(const std::string& s) {
|
||||
std::vector<usize> indices;
|
||||
|
||||
if (s.empty())
|
||||
return indices;
|
||||
@@ -1047,7 +1048,7 @@ class NumaConfig {
|
||||
{
|
||||
const CpuIndex cfirst = CpuIndex{str_to_size_t(std::string(parts[0]))};
|
||||
const CpuIndex clast = CpuIndex{str_to_size_t(std::string(parts[1]))};
|
||||
for (size_t c = cfirst; c <= clast; ++c)
|
||||
for (usize c = cfirst; c <= clast; ++c)
|
||||
{
|
||||
indices.emplace_back(c);
|
||||
}
|
||||
@@ -1088,7 +1089,7 @@ class NumaConfig {
|
||||
else
|
||||
{
|
||||
remove_whitespace(*nodeIdsStr);
|
||||
for (size_t n : indices_from_shortened_string(*nodeIdsStr))
|
||||
for (usize n : indices_from_shortened_string(*nodeIdsStr))
|
||||
{
|
||||
// /sys/devices/system/node/node.../cpulist
|
||||
std::string path =
|
||||
@@ -1105,7 +1106,7 @@ class NumaConfig {
|
||||
else
|
||||
{
|
||||
remove_whitespace(*cpuIdsStr);
|
||||
for (size_t c : indices_from_shortened_string(*cpuIdsStr))
|
||||
for (usize c : indices_from_shortened_string(*cpuIdsStr))
|
||||
{
|
||||
if (is_cpu_allowed(c))
|
||||
cfg.add_cpu_to_node(n, c);
|
||||
@@ -1156,7 +1157,7 @@ class NumaConfig {
|
||||
|
||||
template<typename Pred>
|
||||
static std::optional<NumaConfig> try_get_l3_aware_config(
|
||||
bool respectProcessAffinity, size_t bundleSize, [[maybe_unused]] Pred&& is_cpu_allowed) {
|
||||
bool respectProcessAffinity, usize bundleSize, [[maybe_unused]] Pred&& is_cpu_allowed) {
|
||||
// Get the normal system configuration so we know to which NUMA node
|
||||
// each L3 domain belongs.
|
||||
NumaConfig systemConfig =
|
||||
@@ -1180,7 +1181,7 @@ class NumaConfig {
|
||||
continue;
|
||||
|
||||
L3Domain domain;
|
||||
for (size_t c : indices_from_shortened_string(*siblingsStr))
|
||||
for (usize c : indices_from_shortened_string(*siblingsStr))
|
||||
{
|
||||
if (is_cpu_allowed(c))
|
||||
{
|
||||
@@ -1233,7 +1234,7 @@ class NumaConfig {
|
||||
}
|
||||
|
||||
|
||||
static NumaConfig from_l3_info(std::vector<L3Domain>&& domains, size_t bundleSize) {
|
||||
static NumaConfig from_l3_info(std::vector<L3Domain>&& domains, usize bundleSize) {
|
||||
assert(!domains.empty());
|
||||
|
||||
std::map<NumaIndex, std::vector<L3Domain>> list;
|
||||
@@ -1250,7 +1251,7 @@ class NumaConfig {
|
||||
do
|
||||
{
|
||||
changed = false;
|
||||
for (size_t j = 0; j + 1 < ds.size(); ++j)
|
||||
for (usize j = 0; j + 1 < ds.size(); ++j)
|
||||
{
|
||||
if (ds[j].cpus.size() + ds[j + 1].cpus.size() <= bundleSize)
|
||||
{
|
||||
@@ -1574,14 +1575,14 @@ class LazyNumaReplicatedSystemWide: public NumaReplicatedBase {
|
||||
mutable std::vector<SystemWideSharedConstant<T>> instances;
|
||||
mutable std::mutex mutex;
|
||||
|
||||
std::size_t get_discriminator(NumaIndex idx) const {
|
||||
usize get_discriminator(NumaIndex idx) const {
|
||||
const NumaConfig& cfg = get_numa_config();
|
||||
const NumaConfig& cfg_sys = NumaConfig::from_system(SystemNumaPolicy{}, false);
|
||||
// as a discriminator, locate the hardware/system numadomain this cpuindex belongs to
|
||||
CpuIndex cpu = *cfg.nodes[idx].begin(); // get a CpuIndex from NumaIndex
|
||||
NumaIndex sys_idx = cfg_sys.is_cpu_assigned(cpu) ? cfg_sys.nodeByCpu.at(cpu) : 0;
|
||||
std::string s = cfg_sys.to_string() + "$" + std::to_string(sys_idx);
|
||||
return static_cast<std::size_t>(hash_string(s));
|
||||
return static_cast<usize>(hash_string(s));
|
||||
}
|
||||
|
||||
void ensure_present(NumaIndex idx) const {
|
||||
|
||||
+3
-3
@@ -31,11 +31,11 @@ namespace Stockfish::Benchmark {
|
||||
// Utility to verify move generation. All the leaf nodes up
|
||||
// to the given depth are generated and counted, and the sum is returned.
|
||||
template<bool Root>
|
||||
uint64_t perft(Position& pos, Depth depth) {
|
||||
u64 perft(Position& pos, Depth depth) {
|
||||
|
||||
StateInfo st;
|
||||
|
||||
uint64_t cnt, nodes = 0;
|
||||
u64 cnt, nodes = 0;
|
||||
const bool leaf = (depth == 2);
|
||||
|
||||
for (const auto& m : MoveList<LEGAL>(pos))
|
||||
@@ -55,7 +55,7 @@ uint64_t perft(Position& pos, Depth depth) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
inline uint64_t perft(const std::string& fen, Depth depth, bool isChess960) {
|
||||
inline u64 perft(const std::string& fen, Depth depth, bool isChess960) {
|
||||
StateInfo st;
|
||||
Position p;
|
||||
p.set(fen, isChess960, &st);
|
||||
|
||||
+1
-1
@@ -252,7 +252,7 @@ Position::set(const string& fenStr, bool isChess960, StateInfo* si) {
|
||||
if (file >= FILE_NB)
|
||||
return PositionSetError("Invalid FEN. Invalid file reached.");
|
||||
|
||||
const size_t idx = PieceToChar.find(token);
|
||||
const usize idx = PieceToChar.find(token);
|
||||
if (idx == string::npos)
|
||||
return PositionSetError(std::string("Invalid FEN. Invalid piece: ")
|
||||
+ std::string(1, token));
|
||||
|
||||
+22
-25
@@ -24,7 +24,6 @@
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <initializer_list>
|
||||
#include <iostream>
|
||||
@@ -67,7 +66,7 @@ using namespace Search;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint64_t NODES_LIMIT_OUTPUT = 10'000'000;
|
||||
constexpr u64 NODES_LIMIT_OUTPUT = 10'000'000;
|
||||
|
||||
constexpr int SEARCHEDLIST_CAPACITY = 32;
|
||||
using SearchedList = ValueList<Move, SEARCHEDLIST_CAPACITY>;
|
||||
@@ -130,7 +129,7 @@ void update_correction_history(const Position& pos,
|
||||
}
|
||||
|
||||
// Add a small random component to draw evaluations to avoid 3-fold blindness
|
||||
Value value_draw(size_t nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); }
|
||||
Value value_draw(usize nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); }
|
||||
Value value_to_tt(Value v, int ply);
|
||||
Value value_from_tt(Value v, int ply, int r50c);
|
||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
||||
@@ -160,9 +159,9 @@ bool is_shuffling(Move move, Stack* const ss, const Position& pos) {
|
||||
|
||||
Search::Worker::Worker(SharedState& sharedState,
|
||||
std::unique_ptr<ISearchManager> sm,
|
||||
size_t threadId,
|
||||
size_t numaThreadId,
|
||||
size_t numaTotalThreads,
|
||||
usize threadId,
|
||||
usize numaThreadId,
|
||||
usize numaTotalThreads,
|
||||
NumaReplicatedAccessToken token) :
|
||||
// Unpack the SharedState struct into member variables
|
||||
sharedHistory(sharedState.sharedHistories.at(token.get_numa_index())),
|
||||
@@ -306,13 +305,13 @@ bool Search::Worker::iterative_deepening() {
|
||||
mainThread->iterValue.fill(mainThread->bestPreviousScore);
|
||||
}
|
||||
|
||||
size_t multiPV = size_t(options["MultiPV"]);
|
||||
usize multiPV = usize(options["MultiPV"]);
|
||||
Skill skill(options["Skill Level"], options["UCI_LimitStrength"] ? int(options["UCI_Elo"]) : 0);
|
||||
|
||||
// When playing with strength handicap enable MultiPV search that we will
|
||||
// use behind-the-scenes to retrieve a set of possible moves.
|
||||
if (skill.enabled())
|
||||
multiPV = std::max(multiPV, size_t(4));
|
||||
multiPV = std::max(multiPV, usize(4));
|
||||
|
||||
multiPV = std::min(multiPV, rootMoves.size());
|
||||
|
||||
@@ -343,8 +342,8 @@ bool Search::Worker::iterative_deepening() {
|
||||
for (RootMove& rm : rootMoves)
|
||||
rm.previousScore = rm.score;
|
||||
|
||||
size_t pvFirst = 0;
|
||||
pvLast = 0;
|
||||
usize pvFirst = 0;
|
||||
pvLast = 0;
|
||||
|
||||
if (!threads.increaseDepth)
|
||||
searchAgainCounter++;
|
||||
@@ -530,8 +529,7 @@ bool Search::Worker::iterative_deepening() {
|
||||
// Do we have time for the next iteration? Can we stop searching now?
|
||||
if (limits.use_time_management() && !threads.stop && !mainThread->stopOnPonderhit)
|
||||
{
|
||||
uint64_t nodesEffort =
|
||||
rootMoves[0].effort * 100000 / std::max(uint64_t(1), uint64_t(nodes));
|
||||
u64 nodesEffort = rootMoves[0].effort * 100000 / std::max(u64(1), u64(nodes));
|
||||
|
||||
double fallingEval = (11.87 + 2.21 * (mainThread->bestPreviousAverageScore - bestValue)
|
||||
+ 1.0 * (mainThread->iterValue[iterIdx] - bestValue))
|
||||
@@ -548,8 +546,7 @@ bool Search::Worker::iterative_deepening() {
|
||||
double bestMoveInstability = 1.096 + 2.29 * totBestMoveChanges / threads.size();
|
||||
|
||||
double highBestMoveEffort = std::clamp(
|
||||
interpolate(int64_t(nodesEffort), int64_t(79219), int64_t(101822), 0.924, 0.71), 0.71,
|
||||
0.924);
|
||||
interpolate(i64(nodesEffort), i64(79219), i64(101822), 0.924, 0.71), 0.71, 0.924);
|
||||
|
||||
double totalTime = mainThread->tm.optimum() * fallingEval * reduction
|
||||
* bestMoveInstability * highBestMoveEffort;
|
||||
@@ -652,7 +649,7 @@ void Search::Worker::clear() {
|
||||
for (auto& h : to)
|
||||
h.fill(-552);
|
||||
|
||||
for (size_t i = 1; i < reductions.size(); ++i)
|
||||
for (usize i = 1; i < reductions.size(); ++i)
|
||||
reductions[i] = int(2834 / 128.0 * std::log(i));
|
||||
|
||||
refreshTable.clear(network[numaAccessToken]);
|
||||
@@ -712,7 +709,7 @@ Value Search::Worker::search(
|
||||
maxValue = VALUE_INFINITE;
|
||||
|
||||
ss->followPV = rootNode
|
||||
|| ((ss - 1)->followPV && static_cast<size_t>(ss->ply - 1) < lastIterationPV.size()
|
||||
|| ((ss - 1)->followPV && static_cast<usize>(ss->ply - 1) < lastIterationPV.size()
|
||||
&& (ss - 1)->currentMove == lastIterationPV[ss->ply - 1]);
|
||||
|
||||
// Check for the available remaining time
|
||||
@@ -1241,7 +1238,7 @@ moves_loop: // When in check, search starts here
|
||||
extension = -2;
|
||||
}
|
||||
|
||||
uint64_t nodeCount = rootNode ? uint64_t(nodes) : 0;
|
||||
u64 nodeCount = rootNode ? u64(nodes) : 0;
|
||||
|
||||
// Step 16. Make the move
|
||||
do_move(pos, move, st, givesCheck, ss);
|
||||
@@ -1885,7 +1882,7 @@ void update_all_stats(const Position& pos,
|
||||
if (!PvNode)
|
||||
// Important: don't remove the cast to a 64-bit number else the multiplication
|
||||
// can overflow on 32-bit platforms which would change the bench signature
|
||||
bonus += bonus * uint64_t(quietsSearched.size() + capturesSearched.size()) / 256;
|
||||
bonus += bonus * u64(quietsSearched.size() + capturesSearched.size()) / 256;
|
||||
|
||||
if (!pos.capture_stage(bestMove))
|
||||
{
|
||||
@@ -1969,7 +1966,7 @@ void update_quiet_histories(
|
||||
|
||||
// When playing with strength handicap, choose the best move among a set of
|
||||
// RootMoves using a statistical rule dependent on 'level'. Idea by Heinz van Saanen.
|
||||
Move Skill::pick_best(const RootMoves& rootMoves, size_t multiPV) {
|
||||
Move Skill::pick_best(const RootMoves& rootMoves, usize multiPV) {
|
||||
static PRNG rng(now()); // PRNG sequence should be non-deterministic
|
||||
|
||||
// RootMoves are already sorted by score in descending order
|
||||
@@ -1981,7 +1978,7 @@ Move Skill::pick_best(const RootMoves& rootMoves, size_t multiPV) {
|
||||
// Choose best move. For each move score we add two terms, both dependent on
|
||||
// weakness. One is deterministic and bigger for weaker levels, and one is
|
||||
// random. Then we choose the move with the resulting highest score.
|
||||
for (size_t i = 0; i < multiPV; ++i)
|
||||
for (usize i = 0; i < multiPV; ++i)
|
||||
{
|
||||
// This is our magic formula
|
||||
int push = int(weakness * int(topScore - rootMoves[i].score)
|
||||
@@ -2058,7 +2055,7 @@ void syzygy_extend_pv(const OptionsMap& options,
|
||||
int ply = 1;
|
||||
|
||||
// Step 1, walk the PV to the last position in TB with correct decisive score
|
||||
while (size_t(ply) < rootMove.pv.size())
|
||||
while (usize(ply) < rootMove.pv.size())
|
||||
{
|
||||
Move& pvMove = rootMove.pv[ply];
|
||||
|
||||
@@ -2154,7 +2151,7 @@ void syzygy_extend_pv(const OptionsMap& options,
|
||||
v = VALUE_DRAW;
|
||||
|
||||
// Undo the PV moves
|
||||
for (size_t i = rootMove.pv.size(); i > 0; --i)
|
||||
for (usize i = rootMove.pv.size(); i > 0; --i)
|
||||
pos.undo_move(rootMove.pv[i - 1]);
|
||||
|
||||
// Inform if we couldn't get a full extension in time
|
||||
@@ -2172,10 +2169,10 @@ void SearchManager::pv(Search::Worker& worker,
|
||||
const auto nodes = threads.nodes_searched();
|
||||
auto& rootMoves = worker.rootMoves;
|
||||
auto& pos = worker.rootPos;
|
||||
size_t multiPV = std::min(size_t(worker.options["MultiPV"]), rootMoves.size());
|
||||
uint64_t tbHits = threads.tb_hits() + (worker.tbConfig.rootInTB ? rootMoves.size() : 0);
|
||||
usize multiPV = std::min(usize(worker.options["MultiPV"]), rootMoves.size());
|
||||
u64 tbHits = threads.tb_hits() + (worker.tbConfig.rootInTB ? rootMoves.size() : 0);
|
||||
|
||||
for (size_t i = 0; i < multiPV; ++i)
|
||||
for (usize i = 0; i < multiPV; ++i)
|
||||
{
|
||||
bool usePreviousScore = rootMoves[i].score == -VALUE_INFINITE;
|
||||
|
||||
|
||||
+35
-36
@@ -23,7 +23,6 @@
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -59,19 +58,19 @@ class OptionsMap;
|
||||
namespace Search {
|
||||
|
||||
struct PVMoves {
|
||||
Move moves[MAX_PLY + 1];
|
||||
std::size_t length = 0;
|
||||
Move moves[MAX_PLY + 1];
|
||||
usize length = 0;
|
||||
|
||||
Move* begin() { return moves; }
|
||||
const Move* begin() const { return moves; }
|
||||
Move* end() { return moves + length; }
|
||||
const Move* end() const { return moves + length; }
|
||||
|
||||
Move& operator[](std::size_t index) { return moves[index]; }
|
||||
const Move& operator[](std::size_t index) const { return moves[index]; }
|
||||
Move& operator[](usize index) { return moves[index]; }
|
||||
const Move& operator[](usize index) const { return moves[index]; }
|
||||
|
||||
bool empty() const { return length == 0; }
|
||||
std::size_t size() const { return length; }
|
||||
bool empty() const { return length == 0; }
|
||||
usize size() const { return length; }
|
||||
|
||||
void clear() { length = 0; }
|
||||
|
||||
@@ -80,7 +79,7 @@ struct PVMoves {
|
||||
moves[length++] = move;
|
||||
}
|
||||
|
||||
void resize(std::size_t newSize) {
|
||||
void resize(usize newSize) {
|
||||
assert(newSize <= length);
|
||||
length = newSize;
|
||||
}
|
||||
@@ -136,18 +135,18 @@ struct RootMove {
|
||||
return m.score != score ? m.score < score : m.previousScore < previousScore;
|
||||
}
|
||||
|
||||
uint64_t effort = 0;
|
||||
Value score = -VALUE_INFINITE;
|
||||
Value previousScore = -VALUE_INFINITE;
|
||||
Value averageScore = -VALUE_INFINITE;
|
||||
Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
|
||||
Value uciScore = -VALUE_INFINITE;
|
||||
bool scoreLowerbound = false;
|
||||
bool scoreUpperbound = false;
|
||||
int selDepth = 0;
|
||||
int tbRank = 0;
|
||||
Value tbScore;
|
||||
PVMoves pv;
|
||||
u64 effort = 0;
|
||||
Value score = -VALUE_INFINITE;
|
||||
Value previousScore = -VALUE_INFINITE;
|
||||
Value averageScore = -VALUE_INFINITE;
|
||||
Value meanSquaredScore = -VALUE_INFINITE * VALUE_INFINITE;
|
||||
Value uciScore = -VALUE_INFINITE;
|
||||
bool scoreLowerbound = false;
|
||||
bool scoreUpperbound = false;
|
||||
int selDepth = 0;
|
||||
int tbRank = 0;
|
||||
Value tbScore;
|
||||
PVMoves pv;
|
||||
};
|
||||
|
||||
using RootMoves = std::vector<RootMove>;
|
||||
@@ -169,7 +168,7 @@ struct LimitsType {
|
||||
std::vector<std::string> searchmoves;
|
||||
TimePoint time[COLOR_NB], inc[COLOR_NB], npmsec, movetime, startTime;
|
||||
int movestogo, depth, mate, perft, infinite;
|
||||
uint64_t nodes;
|
||||
u64 nodes;
|
||||
bool ponderMode;
|
||||
};
|
||||
|
||||
@@ -212,13 +211,13 @@ struct InfoShort {
|
||||
|
||||
struct InfoFull: InfoShort {
|
||||
int selDepth;
|
||||
size_t multiPV;
|
||||
usize multiPV;
|
||||
std::string_view wdl;
|
||||
std::string_view bound;
|
||||
size_t timeMs;
|
||||
size_t nodes;
|
||||
size_t nps;
|
||||
size_t tbHits;
|
||||
usize timeMs;
|
||||
usize nodes;
|
||||
usize nps;
|
||||
usize tbHits;
|
||||
std::string_view pv;
|
||||
int hashfull;
|
||||
};
|
||||
@@ -226,7 +225,7 @@ struct InfoFull: InfoShort {
|
||||
struct InfoIteration {
|
||||
int depth;
|
||||
std::string_view currmove;
|
||||
size_t currmovenumber;
|
||||
usize currmovenumber;
|
||||
};
|
||||
|
||||
// Skill structure is used to implement strength limit. If we have a UCI_Elo,
|
||||
@@ -251,7 +250,7 @@ struct Skill {
|
||||
}
|
||||
bool enabled() const { return level < 20.0; }
|
||||
bool time_to_pick(Depth depth) const { return depth == 1 + int(level); }
|
||||
Move pick_best(const RootMoves&, size_t multiPV);
|
||||
Move pick_best(const RootMoves&, usize multiPV);
|
||||
|
||||
double level;
|
||||
Move best = Move::none();
|
||||
@@ -295,7 +294,7 @@ class SearchManager: public ISearchManager {
|
||||
Value bestPreviousAverageScore;
|
||||
bool stopOnPonderhit;
|
||||
|
||||
size_t id;
|
||||
usize id;
|
||||
|
||||
const UpdateContext& updates;
|
||||
};
|
||||
@@ -312,9 +311,9 @@ class Worker {
|
||||
public:
|
||||
Worker(SharedState&,
|
||||
std::unique_ptr<ISearchManager>,
|
||||
size_t,
|
||||
size_t,
|
||||
size_t,
|
||||
usize,
|
||||
usize,
|
||||
usize,
|
||||
NumaReplicatedAccessToken);
|
||||
|
||||
// Called at instantiation to initialize reductions tables.
|
||||
@@ -373,9 +372,9 @@ class Worker {
|
||||
|
||||
LimitsType limits;
|
||||
|
||||
size_t pvIdx, pvLast;
|
||||
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
|
||||
int selDepth, nmpMinPly;
|
||||
usize pvIdx, pvLast;
|
||||
std::atomic<u64> nodes, tbHits, bestMoveChanges;
|
||||
int selDepth, nmpMinPly;
|
||||
|
||||
Value optimism[COLOR_NB];
|
||||
|
||||
@@ -387,7 +386,7 @@ class Worker {
|
||||
|
||||
PVMoves lastIterationPV;
|
||||
|
||||
size_t threadIdx, numaThreadIdx, numaTotal;
|
||||
usize threadIdx, numaThreadIdx, numaTotal;
|
||||
NumaReplicatedAccessToken numaAccessToken;
|
||||
|
||||
// Reductions lookup table initialized at startup
|
||||
|
||||
@@ -100,14 +100,14 @@ namespace Stockfish {
|
||||
// amount of bytes of the path; in particular it can a hash of an empty string.
|
||||
|
||||
inline std::string getExecutablePathHash() {
|
||||
char executable_path[4096] = {0};
|
||||
std::size_t path_length = 0;
|
||||
char executable_path[4096] = {0};
|
||||
usize path_length = 0;
|
||||
|
||||
#if defined(_WIN32)
|
||||
path_length = GetModuleFileNameA(NULL, executable_path, sizeof(executable_path));
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
uint32_t size = sizeof(executable_path);
|
||||
u32 size = sizeof(executable_path);
|
||||
if (_NSGetExecutablePath(executable_path, &size) == 0)
|
||||
{
|
||||
path_length = std::strlen(executable_path);
|
||||
@@ -122,8 +122,8 @@ inline std::string getExecutablePathHash() {
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
size_t size = sizeof(executable_path);
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
usize size = sizeof(executable_path);
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
if (sysctl(mib, 4, executable_path, &size, NULL, 0) == 0)
|
||||
{
|
||||
path_length = std::strlen(executable_path);
|
||||
@@ -171,10 +171,10 @@ inline std::string GetLastErrorAsString(DWORD error) {
|
||||
|
||||
//Ask Win32 to give us the string version of that message ID.
|
||||
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
|
||||
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &messageBuffer, 0, NULL);
|
||||
usize size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR) &messageBuffer, 0, NULL);
|
||||
|
||||
//Copy the error message into a std::string.
|
||||
std::string message(messageBuffer, size);
|
||||
@@ -278,12 +278,12 @@ class SharedMemoryBackend {
|
||||
|
||||
private:
|
||||
void initialize(const std::string& shm_name, const T& value) {
|
||||
const size_t total_size = sizeof(T) + sizeof(IS_INITIALIZED_VALUE);
|
||||
const usize total_size = sizeof(T) + sizeof(IS_INITIALIZED_VALUE);
|
||||
|
||||
// Try allocating with large pages first.
|
||||
hMapFile = windows_try_with_large_page_priviliges(
|
||||
[&](size_t largePageSize) {
|
||||
const size_t total_size_aligned =
|
||||
[&](usize largePageSize) {
|
||||
const usize total_size_aligned =
|
||||
(total_size + largePageSize - 1) / largePageSize * largePageSize;
|
||||
|
||||
#if defined(_WIN64)
|
||||
@@ -530,9 +530,9 @@ struct SystemWideSharedConstant {
|
||||
|
||||
// Content is addressed by its hash. An additional discriminator can be added to account for differences
|
||||
// that are not present in the content, for example NUMA node allocation.
|
||||
SystemWideSharedConstant(const T& value, std::size_t discriminator = 0) {
|
||||
std::size_t content_hash = std::hash<T>{}(value);
|
||||
std::size_t executable_hash = hash_string(getExecutablePathHash());
|
||||
SystemWideSharedConstant(const T& value, usize discriminator = 0) {
|
||||
usize content_hash = std::hash<T>{}(value);
|
||||
usize executable_hash = hash_string(getExecutablePathHash());
|
||||
|
||||
char buf[1024];
|
||||
std::snprintf(buf, sizeof(buf), "Local\\sf_%zu$%zu$%zu", content_hash, executable_hash,
|
||||
|
||||
+10
-10
@@ -54,11 +54,11 @@ namespace Stockfish::shm {
|
||||
namespace detail {
|
||||
|
||||
struct ShmHeader {
|
||||
static constexpr uint32_t SHM_MAGIC = 0xAD5F1A12;
|
||||
pthread_mutex_t mutex;
|
||||
std::atomic<uint32_t> ref_count{0};
|
||||
std::atomic<bool> initialized{false};
|
||||
uint32_t magic = SHM_MAGIC;
|
||||
static constexpr u32 SHM_MAGIC = 0xAD5F1A12;
|
||||
pthread_mutex_t mutex;
|
||||
std::atomic<u32> ref_count{0};
|
||||
std::atomic<bool> initialized{false};
|
||||
u32 magic = SHM_MAGIC;
|
||||
};
|
||||
|
||||
class SharedMemoryBase {
|
||||
@@ -154,11 +154,11 @@ class SharedMemory: public detail::SharedMemoryBase {
|
||||
void* mapped_ptr_ = nullptr;
|
||||
T* data_ptr_ = nullptr;
|
||||
detail::ShmHeader* header_ptr_ = nullptr;
|
||||
size_t total_size_ = 0;
|
||||
usize total_size_ = 0;
|
||||
std::string sentinel_base_;
|
||||
std::string sentinel_path_;
|
||||
|
||||
static constexpr size_t calculate_total_size() noexcept {
|
||||
static constexpr usize calculate_total_size() noexcept {
|
||||
return sizeof(T) + sizeof(detail::ShmHeader);
|
||||
}
|
||||
|
||||
@@ -370,7 +370,7 @@ class SharedMemory: public detail::SharedMemoryBase {
|
||||
|
||||
[[nodiscard]] const T& operator*() const noexcept { return *data_ptr_; }
|
||||
|
||||
[[nodiscard]] uint32_t ref_count() const noexcept {
|
||||
[[nodiscard]] u32 ref_count() const noexcept {
|
||||
return header_ptr_ ? header_ptr_->ref_count.load(std::memory_order_acquire) : 0;
|
||||
}
|
||||
|
||||
@@ -435,7 +435,7 @@ class SharedMemory: public detail::SharedMemoryBase {
|
||||
if (!header_ptr_)
|
||||
return;
|
||||
|
||||
uint32_t expected = header_ptr_->ref_count.load(std::memory_order_relaxed);
|
||||
u32 expected = header_ptr_->ref_count.load(std::memory_order_relaxed);
|
||||
while (expected != 0
|
||||
&& !header_ptr_->ref_count.compare_exchange_weak(
|
||||
expected, expected - 1, std::memory_order_acq_rel, std::memory_order_relaxed))
|
||||
@@ -631,7 +631,7 @@ class SharedMemory: public detail::SharedMemoryBase {
|
||||
|
||||
struct stat st;
|
||||
fstat(fd_, &st);
|
||||
if (static_cast<size_t>(st.st_size) < total_size_)
|
||||
if (static_cast<usize>(st.st_size) < total_size_)
|
||||
{
|
||||
invalid_header = true;
|
||||
return false;
|
||||
|
||||
+77
-78
@@ -115,12 +115,12 @@ template<typename T, int Half = sizeof(T) / 2, int End = sizeof(T) - 1>
|
||||
inline void swap_endian(T& x) {
|
||||
static_assert(std::is_unsigned_v<T>, "Argument of swap_endian not unsigned");
|
||||
|
||||
uint8_t tmp, *c = (uint8_t*) &x;
|
||||
u8 tmp, *c = (u8*) &x;
|
||||
for (int i = 0; i < Half; ++i)
|
||||
tmp = c[i], c[i] = c[End - i], c[End - i] = tmp;
|
||||
}
|
||||
template<>
|
||||
inline void swap_endian<uint8_t>(uint8_t&) {}
|
||||
inline void swap_endian<u8>(u8&) {}
|
||||
|
||||
template<typename T, int LE>
|
||||
T number(void* addr) {
|
||||
@@ -161,7 +161,7 @@ struct SparseEntry {
|
||||
|
||||
static_assert(sizeof(SparseEntry) == 6, "SparseEntry must be 6 bytes");
|
||||
|
||||
using Sym = uint16_t; // Huffman symbol
|
||||
using Sym = u16; // Huffman symbol
|
||||
|
||||
struct LR {
|
||||
enum Side {
|
||||
@@ -169,9 +169,9 @@ struct LR {
|
||||
Right
|
||||
};
|
||||
|
||||
uint8_t lr[3]; // The first 12 bits is the left-hand symbol, the second 12
|
||||
// bits is the right-hand symbol. If the symbol has length 1,
|
||||
// then the left-hand symbol is the stored value.
|
||||
u8 lr[3]; // The first 12 bits is the left-hand symbol, the second 12
|
||||
// bits is the right-hand symbol. If the symbol has length 1,
|
||||
// then the left-hand symbol is the stored value.
|
||||
template<Side S>
|
||||
Sym get() {
|
||||
return S == Left ? ((lr[1] & 0xF) << 8) | lr[0]
|
||||
@@ -224,7 +224,7 @@ class TBFile: public std::ifstream {
|
||||
}
|
||||
|
||||
// Memory map the file and check it.
|
||||
uint8_t* map(void** baseAddress, uint64_t* mapping, TBType type) {
|
||||
u8* map(void** baseAddress, u64* mapping, TBType type) {
|
||||
if (is_open())
|
||||
close(); // Need to re-open to get native file descriptor
|
||||
|
||||
@@ -281,7 +281,7 @@ class TBFile: public std::ifstream {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
*mapping = uint64_t(mmap);
|
||||
*mapping = u64(mmap);
|
||||
*baseAddress = MapViewOfFile(mmap, FILE_MAP_READ, 0, 0, 0);
|
||||
|
||||
if (!*baseAddress)
|
||||
@@ -291,9 +291,9 @@ class TBFile: public std::ifstream {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
uint8_t* data = (uint8_t*) *baseAddress;
|
||||
u8* data = (u8*) *baseAddress;
|
||||
|
||||
constexpr uint8_t Magics[][4] = {{0xD7, 0x66, 0x0C, 0xA5}, {0x71, 0xE8, 0x23, 0x5D}};
|
||||
constexpr u8 Magics[][4] = {{0xD7, 0x66, 0x0C, 0xA5}, {0x71, 0xE8, 0x23, 0x5D}};
|
||||
|
||||
if (memcmp(data, Magics[type == WDL], 4))
|
||||
{
|
||||
@@ -305,7 +305,7 @@ class TBFile: public std::ifstream {
|
||||
return data + 4; // Skip Magics's header
|
||||
}
|
||||
|
||||
static void unmap(void* baseAddress, uint64_t mapping) {
|
||||
static void unmap(void* baseAddress, u64 mapping) {
|
||||
|
||||
#ifndef _WIN32
|
||||
munmap(baseAddress, mapping);
|
||||
@@ -322,27 +322,26 @@ std::string TBFile::Paths;
|
||||
// There are 8, 4, or 2 PairsData records for each TBTable, according to the type
|
||||
// of table and if positions have pawns or not. It is populated at first access.
|
||||
struct PairsData {
|
||||
uint8_t flags; // Table flags, see enum TBFlag
|
||||
uint8_t maxSymLen; // Maximum length in bits of the Huffman symbols
|
||||
uint8_t minSymLen; // Minimum length in bits of the Huffman symbols
|
||||
uint32_t blocksNum; // Number of blocks in the TB file
|
||||
size_t sizeofBlock; // Block size in bytes
|
||||
size_t span; // About every span values there is a SparseIndex[] entry
|
||||
Sym* lowestSym; // lowestSym[l] is the symbol of length l with the lowest value
|
||||
LR* btree; // btree[sym] stores the left and right symbols that expand sym
|
||||
uint16_t* blockLength; // Number of stored positions (minus one) for each block: 1..65536
|
||||
uint32_t blockLengthSize; // Size of blockLength[] table: padded so it's bigger than blocksNum
|
||||
SparseEntry* sparseIndex; // Partial indices into blockLength[]
|
||||
size_t sparseIndexSize; // Size of SparseIndex[] table
|
||||
uint8_t* data; // Start of Huffman compressed data
|
||||
std::vector<uint64_t>
|
||||
u8 flags; // Table flags, see enum TBFlag
|
||||
u8 maxSymLen; // Maximum length in bits of the Huffman symbols
|
||||
u8 minSymLen; // Minimum length in bits of the Huffman symbols
|
||||
u32 blocksNum; // Number of blocks in the TB file
|
||||
usize sizeofBlock; // Block size in bytes
|
||||
usize span; // About every span values there is a SparseIndex[] entry
|
||||
Sym* lowestSym; // lowestSym[l] is the symbol of length l with the lowest value
|
||||
LR* btree; // btree[sym] stores the left and right symbols that expand sym
|
||||
u16* blockLength; // Number of stored positions (minus one) for each block: 1..65536
|
||||
u32 blockLengthSize; // Size of blockLength[] table: padded so it's bigger than blocksNum
|
||||
SparseEntry* sparseIndex; // Partial indices into blockLength[]
|
||||
usize sparseIndexSize; // Size of SparseIndex[] table
|
||||
u8* data; // Start of Huffman compressed data
|
||||
std::vector<u64>
|
||||
base64; // base64[l - min_sym_len] is the 64bit-padded lowest symbol of length l
|
||||
std::vector<uint8_t>
|
||||
symlen; // Number of values (-1) represented by a given Huffman symbol: 1..256
|
||||
Piece pieces[TBPIECES]; // Position pieces: the order of pieces defines the groups
|
||||
uint64_t groupIdx[TBPIECES + 1]; // Start index used for the encoding of the group's pieces
|
||||
int groupLen[TBPIECES + 1]; // Number of pieces in a given group: KRKN -> (3, 1)
|
||||
uint16_t map_idx[4]; // WDLWin, WDLLoss, WDLCursedWin, WDLBlessedLoss (used in DTZ)
|
||||
std::vector<u8> symlen; // Number of values (-1) represented by a given Huffman symbol: 1..256
|
||||
Piece pieces[TBPIECES]; // Position pieces: the order of pieces defines the groups
|
||||
u64 groupIdx[TBPIECES + 1]; // Start index used for the encoding of the group's pieces
|
||||
int groupLen[TBPIECES + 1]; // Number of pieces in a given group: KRKN -> (3, 1)
|
||||
u16 map_idx[4]; // WDLWin, WDLLoss, WDLCursedWin, WDLBlessedLoss (used in DTZ)
|
||||
};
|
||||
|
||||
// struct TBTable contains indexing information to access the corresponding TBFile.
|
||||
@@ -357,14 +356,14 @@ struct TBTable {
|
||||
|
||||
std::atomic_bool ready;
|
||||
void* baseAddress;
|
||||
uint8_t* map;
|
||||
uint64_t mapping;
|
||||
u8* map;
|
||||
u64 mapping;
|
||||
Key key;
|
||||
Key key2;
|
||||
int pieceCount;
|
||||
bool hasPawns;
|
||||
bool hasUniquePieces;
|
||||
uint8_t pawnCount[2]; // [Lead color / other color]
|
||||
u8 pawnCount[2]; // [Lead color / other color]
|
||||
PairsData items[Sides][4]; // [wtm / btm][FILE_A..FILE_D or 0]
|
||||
|
||||
PairsData* get(int stm, int f) { return &items[stm % Sides][hasPawns ? f : 0]; }
|
||||
@@ -464,15 +463,15 @@ class TBTables {
|
||||
|
||||
std::deque<TBTable<WDL>> wdlTable;
|
||||
std::deque<TBTable<DTZ>> dtzTable;
|
||||
size_t foundDTZFiles = 0;
|
||||
size_t foundWDLFiles = 0;
|
||||
usize foundDTZFiles = 0;
|
||||
usize foundWDLFiles = 0;
|
||||
|
||||
void insert(Key key, TBTable<WDL>* wdl, TBTable<DTZ>* dtz) {
|
||||
uint32_t homeBucket = uint32_t(key) & (Size - 1);
|
||||
Entry entry{key, wdl, dtz};
|
||||
u32 homeBucket = u32(key) & (Size - 1);
|
||||
Entry entry{key, wdl, dtz};
|
||||
|
||||
// Ensure last element is empty to avoid overflow when looking up
|
||||
for (uint32_t bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket)
|
||||
for (u32 bucket = homeBucket; bucket < Size + Overflow - 1; ++bucket)
|
||||
{
|
||||
Key otherKey = hashTable[bucket].key;
|
||||
if (otherKey == key || !hashTable[bucket].get<WDL>())
|
||||
@@ -483,7 +482,7 @@ class TBTables {
|
||||
|
||||
// Robin Hood hashing: If we've probed for longer than this element,
|
||||
// insert here and search for a new spot for the other element instead.
|
||||
uint32_t otherHomeBucket = uint32_t(otherKey) & (Size - 1);
|
||||
u32 otherHomeBucket = u32(otherKey) & (Size - 1);
|
||||
if (otherHomeBucket > homeBucket)
|
||||
{
|
||||
std::swap(entry, hashTable[bucket]);
|
||||
@@ -498,7 +497,7 @@ class TBTables {
|
||||
public:
|
||||
template<TBType Type>
|
||||
TBTable<Type>* get(Key key) {
|
||||
for (const Entry* entry = &hashTable[uint32_t(key) & (Size - 1)];; ++entry)
|
||||
for (const Entry* entry = &hashTable[u32(key) & (Size - 1)];; ++entry)
|
||||
{
|
||||
if (entry->key == key || !entry->get<Type>())
|
||||
return entry->get<Type>();
|
||||
@@ -573,7 +572,7 @@ void TBTables::add(const std::vector<PieceType>& pieces) {
|
||||
// Huffman codes are the same for all blocks in the table. A non-symmetric pawnless TB file
|
||||
// will have one table for wtm and one for btm, a TB file with pawns will have tables per
|
||||
// file a,b,c,d also, in this case, one set for wtm and one for btm.
|
||||
int decompress_pairs(PairsData* d, uint64_t idx) {
|
||||
int decompress_pairs(PairsData* d, u64 idx) {
|
||||
|
||||
// Special case where all table positions store the same value
|
||||
if (d->flags & TBFlag::SingleValue)
|
||||
@@ -594,11 +593,11 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
|
||||
// I(k) = k * d->span + d->span / 2 (1)
|
||||
|
||||
// First step is to get the 'k' of the I(k) nearest to our idx, using definition (1)
|
||||
uint32_t k = uint32_t(idx / d->span);
|
||||
u32 k = u32(idx / d->span);
|
||||
|
||||
// Then we read the corresponding SparseIndex[] entry
|
||||
uint32_t block = number<uint32_t, LittleEndian>(&d->sparseIndex[k].block);
|
||||
int offset = number<uint16_t, LittleEndian>(&d->sparseIndex[k].offset);
|
||||
u32 block = number<u32, LittleEndian>(&d->sparseIndex[k].block);
|
||||
int offset = number<u16, LittleEndian>(&d->sparseIndex[k].offset);
|
||||
|
||||
// Now compute the difference idx - I(k). From the definition of k, we know that
|
||||
//
|
||||
@@ -619,12 +618,12 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
|
||||
offset -= d->blockLength[block++] + 1;
|
||||
|
||||
// Finally, we find the start address of our block of canonical Huffman symbols
|
||||
uint32_t* ptr = (uint32_t*) (d->data + (uint64_t(block) * d->sizeofBlock));
|
||||
u32* ptr = (u32*) (d->data + (u64(block) * d->sizeofBlock));
|
||||
|
||||
// Read the first 64 bits in our block, this is a (truncated) sequence of
|
||||
// unknown number of symbols of unknown length but we know the first one
|
||||
// is at the beginning of this 64-bit sequence.
|
||||
uint64_t buf64 = number<uint64_t, BigEndian>(ptr);
|
||||
u64 buf64 = number<u64, BigEndian>(ptr);
|
||||
ptr += 2;
|
||||
int buf64Size = 64;
|
||||
Sym sym;
|
||||
@@ -661,7 +660,7 @@ int decompress_pairs(PairsData* d, uint64_t idx) {
|
||||
if (buf64Size <= 32)
|
||||
{ // Refill the buffer
|
||||
buf64Size += 32;
|
||||
buf64 |= uint64_t(number<uint32_t, BigEndian>(ptr++)) << (64 - buf64Size);
|
||||
buf64 |= u64(number<u32, BigEndian>(ptr++)) << (64 - buf64Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,12 +708,12 @@ int map_score(TBTable<DTZ>* entry, File f, int value, WDLScore wdl) {
|
||||
|
||||
auto flags = entry->get(0, f)->flags;
|
||||
|
||||
uint8_t* map = entry->map;
|
||||
uint16_t* idx = entry->get(0, f)->map_idx;
|
||||
u8* map = entry->map;
|
||||
u16* idx = entry->get(0, f)->map_idx;
|
||||
if (flags & TBFlag::Mapped)
|
||||
{
|
||||
if (flags & TBFlag::Wide)
|
||||
value = ((uint16_t*) map)[idx[WDLMap[wdl + 2]] + value];
|
||||
value = ((u16*) map)[idx[WDLMap[wdl + 2]] + value];
|
||||
else
|
||||
value = map[idx[WDLMap[wdl + 2]] + value];
|
||||
}
|
||||
@@ -747,7 +746,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu
|
||||
|
||||
Square squares[TBPIECES];
|
||||
Piece pieces[TBPIECES];
|
||||
uint64_t idx;
|
||||
u64 idx;
|
||||
int next = 0, size = 0, leadPawnsCnt = 0;
|
||||
PairsData* d;
|
||||
Bitboard b, leadPawns = 0;
|
||||
@@ -944,7 +943,7 @@ encode_remaining:
|
||||
while (d->groupLen[++next])
|
||||
{
|
||||
std::stable_sort(groupSq, groupSq + d->groupLen[next]);
|
||||
uint64_t n = 0;
|
||||
u64 n = 0;
|
||||
|
||||
// Map down a square if "comes later" than a square in the previous
|
||||
// groups (similar to what was done earlier for leading group pieces).
|
||||
@@ -1003,10 +1002,10 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
|
||||
// pawns/pieces -> remaining pawns -> remaining pieces. In particular the
|
||||
// first group is at order[0] position and the remaining pawns, when present,
|
||||
// are at order[1] position.
|
||||
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
|
||||
int next = pp ? 2 : 1;
|
||||
int freeSquares = 64 - d->groupLen[0] - (pp ? d->groupLen[1] : 0);
|
||||
uint64_t idx = 1;
|
||||
bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides
|
||||
int next = pp ? 2 : 1;
|
||||
int freeSquares = 64 - d->groupLen[0] - (pp ? d->groupLen[1] : 0);
|
||||
u64 idx = 1;
|
||||
|
||||
for (int k = 0; next < n || k == order[0] || k == order[1]; ++k)
|
||||
if (k == order[0]) // Leading pawns or pieces
|
||||
@@ -1032,7 +1031,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) {
|
||||
// In Recursive Pairing each symbol represents a pair of children symbols. So
|
||||
// read d->btree[] symbols data and expand each one in his left and right child
|
||||
// symbol until reaching the leaves that represent the symbol value.
|
||||
uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
|
||||
u8 set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
|
||||
|
||||
visited[s] = true; // We can set it now because tree is acyclic
|
||||
Sym sr = d->btree[s].get<LR::Right>();
|
||||
@@ -1051,7 +1050,7 @@ uint8_t set_symlen(PairsData* d, Sym s, std::vector<bool>& visited) {
|
||||
return d->symlen[sl] + d->symlen[sr] + 1;
|
||||
}
|
||||
|
||||
uint8_t* set_sizes(PairsData* d, uint8_t* data) {
|
||||
u8* set_sizes(PairsData* d, u8* data) {
|
||||
|
||||
d->flags = *data++;
|
||||
|
||||
@@ -1065,14 +1064,14 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
|
||||
|
||||
// groupLen[] is a zero-terminated list of group lengths, the last groupIdx[]
|
||||
// element stores the biggest index that is the tb size.
|
||||
uint64_t tbSize = d->groupIdx[std::find(d->groupLen, d->groupLen + 7, 0) - d->groupLen];
|
||||
u64 tbSize = d->groupIdx[std::find(d->groupLen, d->groupLen + 7, 0) - d->groupLen];
|
||||
|
||||
d->sizeofBlock = 1ULL << *data++;
|
||||
d->span = 1ULL << *data++;
|
||||
d->sparseIndexSize = size_t((tbSize + d->span - 1) / d->span); // Round up
|
||||
auto padding = number<uint8_t, LittleEndian>(data++);
|
||||
d->blocksNum = number<uint32_t, LittleEndian>(data);
|
||||
data += sizeof(uint32_t);
|
||||
d->sparseIndexSize = usize((tbSize + d->span - 1) / d->span); // Round up
|
||||
auto padding = number<u8, LittleEndian>(data++);
|
||||
d->blocksNum = number<u32, LittleEndian>(data);
|
||||
data += sizeof(u32);
|
||||
d->blockLengthSize = d->blocksNum + padding; // Padded to ensure SparseIndex[]
|
||||
// does not point out of range.
|
||||
d->maxSymLen = *data++;
|
||||
@@ -1109,8 +1108,8 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
|
||||
d->base64[i] <<= 64 - i - d->minSymLen; // Right-padding to 64 bits
|
||||
|
||||
data += base64_size * sizeof(Sym);
|
||||
d->symlen.resize(number<uint16_t, LittleEndian>(data));
|
||||
data += sizeof(uint16_t);
|
||||
d->symlen.resize(number<u16, LittleEndian>(data));
|
||||
data += sizeof(u16);
|
||||
d->btree = (LR*) data;
|
||||
|
||||
// The compression scheme used is "Recursive Pairing", that replaces the most
|
||||
@@ -1127,9 +1126,9 @@ uint8_t* set_sizes(PairsData* d, uint8_t* data) {
|
||||
return data + d->symlen.size() * sizeof(LR) + (d->symlen.size() & 1);
|
||||
}
|
||||
|
||||
uint8_t* set_dtz_map(TBTable<WDL>&, uint8_t* data, File) { return data; }
|
||||
u8* set_dtz_map(TBTable<WDL>&, u8* data, File) { return data; }
|
||||
|
||||
uint8_t* set_dtz_map(TBTable<DTZ>& e, uint8_t* data, File maxFile) {
|
||||
u8* set_dtz_map(TBTable<DTZ>& e, u8* data, File maxFile) {
|
||||
|
||||
e.map = data;
|
||||
|
||||
@@ -1143,15 +1142,15 @@ uint8_t* set_dtz_map(TBTable<DTZ>& e, uint8_t* data, File maxFile) {
|
||||
data += uintptr_t(data) & 1; // Word alignment, we may have a mixed table
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{ // Sequence like 3,x,x,x,1,x,0,2,x,x
|
||||
e.get(0, f)->map_idx[i] = uint16_t((uint16_t*) data - (uint16_t*) e.map + 1);
|
||||
data += 2 * number<uint16_t, LittleEndian>(data) + 2;
|
||||
e.get(0, f)->map_idx[i] = u16((u16*) data - (u16*) e.map + 1);
|
||||
data += 2 * number<u16, LittleEndian>(data) + 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
e.get(0, f)->map_idx[i] = uint16_t(data - e.map + 1);
|
||||
e.get(0, f)->map_idx[i] = u16(data - e.map + 1);
|
||||
data += *data + 1;
|
||||
}
|
||||
}
|
||||
@@ -1164,7 +1163,7 @@ uint8_t* set_dtz_map(TBTable<DTZ>& e, uint8_t* data, File maxFile) {
|
||||
// Populate entry's PairsData records with data from the just memory-mapped file.
|
||||
// Called at first access.
|
||||
template<typename T>
|
||||
void set(T& e, uint8_t* data) {
|
||||
void set(T& e, u8* data) {
|
||||
|
||||
PairsData* d;
|
||||
|
||||
@@ -1221,14 +1220,14 @@ void set(T& e, uint8_t* data) {
|
||||
for (File f = FILE_A; f <= maxFile; ++f)
|
||||
for (int i = 0; i < sides; i++)
|
||||
{
|
||||
(d = e.get(i, f))->blockLength = (uint16_t*) data;
|
||||
data += d->blockLengthSize * sizeof(uint16_t);
|
||||
(d = e.get(i, f))->blockLength = (u16*) data;
|
||||
data += d->blockLengthSize * sizeof(u16);
|
||||
}
|
||||
|
||||
for (File f = FILE_A; f <= maxFile; ++f)
|
||||
for (int i = 0; i < sides; i++)
|
||||
{
|
||||
data = (uint8_t*) ((uintptr_t(data) + 0x3F) & ~0x3F); // 64 byte alignment
|
||||
data = (u8*) ((uintptr_t(data) + 0x3F) & ~0x3F); // 64 byte alignment
|
||||
(d = e.get(i, f))->data = data;
|
||||
data += d->blocksNum * d->sizeofBlock;
|
||||
}
|
||||
@@ -1266,7 +1265,7 @@ void* mapped(TBTable<Type>& e, const Position& pos) {
|
||||
fname =
|
||||
(e.key == pos.material_key() ? w + 'v' + b : b + 'v' + w) + (Type == WDL ? ".rtbw" : ".rtbz");
|
||||
|
||||
uint8_t* data = TBFile(fname).map(&e.baseAddress, &e.mapping, Type);
|
||||
u8* data = TBFile(fname).map(&e.baseAddress, &e.mapping, Type);
|
||||
|
||||
if (data)
|
||||
set(e, data);
|
||||
@@ -1308,8 +1307,8 @@ WDLScore search(Position& pos, ProbeState* result) {
|
||||
WDLScore value, bestValue = WDLLoss;
|
||||
StateInfo st;
|
||||
|
||||
auto moveList = MoveList<LEGAL>(pos);
|
||||
size_t totalCount = moveList.size(), moveCount = 0;
|
||||
auto moveList = MoveList<LEGAL>(pos);
|
||||
usize totalCount = moveList.size(), moveCount = 0;
|
||||
|
||||
for (const Move move : moveList)
|
||||
{
|
||||
|
||||
+21
-21
@@ -47,9 +47,9 @@ namespace Stockfish {
|
||||
// in idle_loop(). Note that 'searching' and 'exit' should be already set.
|
||||
Thread::Thread(Search::SharedState& sharedState,
|
||||
std::unique_ptr<Search::ISearchManager> sm,
|
||||
size_t n,
|
||||
size_t numaN,
|
||||
size_t totalNumaCount,
|
||||
usize n,
|
||||
usize numaN,
|
||||
usize totalNumaCount,
|
||||
OptionalThreadToNumaNodeBinder binder) :
|
||||
idx(n),
|
||||
idxInNuma(numaN),
|
||||
@@ -141,10 +141,10 @@ void Thread::idle_loop() {
|
||||
|
||||
Search::SearchManager* ThreadPool::main_manager() { return main_thread()->worker->main_manager(); }
|
||||
|
||||
uint64_t ThreadPool::nodes_searched() const { return accumulate(&Search::Worker::nodes); }
|
||||
uint64_t ThreadPool::tb_hits() const { return accumulate(&Search::Worker::tbHits); }
|
||||
u64 ThreadPool::nodes_searched() const { return accumulate(&Search::Worker::nodes); }
|
||||
u64 ThreadPool::tb_hits() const { return accumulate(&Search::Worker::tbHits); }
|
||||
|
||||
static size_t next_power_of_two(uint64_t count) { return count > 1 ? (2ULL << msb(count - 1)) : 1; }
|
||||
static usize next_power_of_two(u64 count) { return count > 1 ? (2ULL << msb(count - 1)) : 1; }
|
||||
|
||||
// Creates/destroys threads to match the requested number.
|
||||
// Created and launched threads will immediately go to sleep in idle_loop.
|
||||
@@ -162,7 +162,7 @@ void ThreadPool::set(const NumaConfig& numaConfig,
|
||||
boundThreadToNumaNode.clear();
|
||||
}
|
||||
|
||||
const size_t requested = sharedState.options["Threads"];
|
||||
const usize requested = sharedState.options["Threads"];
|
||||
|
||||
if (requested > 0) // create new thread(s)
|
||||
{
|
||||
@@ -184,7 +184,7 @@ void ThreadPool::set(const NumaConfig& numaConfig,
|
||||
return true;
|
||||
}();
|
||||
|
||||
std::map<NumaIndex, size_t> counts;
|
||||
std::map<NumaIndex, usize> counts;
|
||||
boundThreadToNumaNode = doBindThreads
|
||||
? numaConfig.distribute_threads_among_numa_nodes(requested)
|
||||
: std::vector<NumaIndex>{};
|
||||
@@ -193,7 +193,7 @@ void ThreadPool::set(const NumaConfig& numaConfig,
|
||||
counts[0] = requested; // Pretend all threads are part of numa node 0
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < boundThreadToNumaNode.size(); ++i)
|
||||
for (usize i = 0; i < boundThreadToNumaNode.size(); ++i)
|
||||
counts[boundThreadToNumaNode[i]]++;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ void ThreadPool::set(const NumaConfig& numaConfig,
|
||||
for (auto pair : counts)
|
||||
{
|
||||
NumaIndex numaIndex = pair.first;
|
||||
uint64_t count = pair.second;
|
||||
u64 count = pair.second;
|
||||
auto f = [&]() {
|
||||
sharedState.sharedHistories.try_emplace(numaIndex, next_power_of_two(count));
|
||||
};
|
||||
@@ -216,7 +216,7 @@ void ThreadPool::set(const NumaConfig& numaConfig,
|
||||
|
||||
while (threads.size() < requested)
|
||||
{
|
||||
const size_t threadId = threads.size();
|
||||
const usize threadId = threads.size();
|
||||
const NumaIndex numaId = doBindThreads ? boundThreadToNumaNode[threadId] : 0;
|
||||
auto create_thread = [&]() {
|
||||
auto manager = threadId == 0
|
||||
@@ -271,17 +271,17 @@ void ThreadPool::clear() {
|
||||
main_manager()->tm.clear();
|
||||
}
|
||||
|
||||
void ThreadPool::run_on_thread(size_t threadId, std::function<void()> f) {
|
||||
void ThreadPool::run_on_thread(usize threadId, std::function<void()> f) {
|
||||
assert(threads.size() > threadId);
|
||||
threads[threadId]->run_custom_job(std::move(f));
|
||||
}
|
||||
|
||||
void ThreadPool::wait_on_thread(size_t threadId) {
|
||||
void ThreadPool::wait_on_thread(usize threadId) {
|
||||
assert(threads.size() > threadId);
|
||||
threads[threadId]->wait_for_search_finished();
|
||||
}
|
||||
|
||||
size_t ThreadPool::num_threads() const { return threads.size(); }
|
||||
usize ThreadPool::num_threads() const { return threads.size(); }
|
||||
|
||||
|
||||
// Wakes up main thread waiting in idle_loop() and returns immediately.
|
||||
@@ -352,7 +352,7 @@ Thread* ThreadPool::get_best_thread() const {
|
||||
Thread* bestThread = threads.front().get();
|
||||
Value minScore = VALUE_NONE;
|
||||
|
||||
std::unordered_map<Move, int64_t, Move::MoveHash> votes(
|
||||
std::unordered_map<Move, i64, Move::MoveHash> votes(
|
||||
2 * std::min(size(), bestThread->worker->rootMoves.size()));
|
||||
|
||||
// Find the minimum score of all threads
|
||||
@@ -428,12 +428,12 @@ void ThreadPool::wait_for_search_finished() const {
|
||||
th->wait_for_search_finished();
|
||||
}
|
||||
|
||||
std::vector<size_t> ThreadPool::get_bound_thread_to_numa_node() const {
|
||||
std::vector<usize> ThreadPool::get_bound_thread_to_numa_node() const {
|
||||
return boundThreadToNumaNode;
|
||||
}
|
||||
|
||||
std::vector<size_t> ThreadPool::get_bound_thread_count_by_numa_node() const {
|
||||
std::vector<size_t> counts;
|
||||
std::vector<usize> ThreadPool::get_bound_thread_count_by_numa_node() const {
|
||||
std::vector<usize> counts;
|
||||
|
||||
if (!boundThreadToNumaNode.empty())
|
||||
{
|
||||
@@ -451,11 +451,11 @@ std::vector<size_t> ThreadPool::get_bound_thread_count_by_numa_node() const {
|
||||
return counts;
|
||||
}
|
||||
|
||||
size_t ThreadPool::numa_nodes() const {
|
||||
std::unordered_set<size_t> seen;
|
||||
usize ThreadPool::numa_nodes() const {
|
||||
std::unordered_set<usize> seen;
|
||||
for (NumaIndex n : boundThreadToNumaNode)
|
||||
seen.insert(n);
|
||||
return std::max(seen.size(), size_t(1));
|
||||
return std::max(seen.size(), usize(1));
|
||||
}
|
||||
|
||||
void ThreadPool::ensure_network_replicated() {
|
||||
|
||||
+22
-23
@@ -21,13 +21,12 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "misc.h"
|
||||
#include "memory.h"
|
||||
#include "numa.h"
|
||||
#include "position.h"
|
||||
@@ -75,9 +74,9 @@ class Thread {
|
||||
public:
|
||||
Thread(Search::SharedState&,
|
||||
std::unique_ptr<Search::ISearchManager>,
|
||||
size_t,
|
||||
size_t,
|
||||
size_t,
|
||||
usize,
|
||||
usize,
|
||||
usize,
|
||||
OptionalThreadToNumaNodeBinder);
|
||||
virtual ~Thread();
|
||||
|
||||
@@ -93,8 +92,8 @@ class Thread {
|
||||
// require further work to make them properly generic while maintaining
|
||||
// appropriate specificity regarding search, from the point of view of an
|
||||
// outside user, so renaming of this function is left for whenever that happens.
|
||||
void wait_for_search_finished();
|
||||
size_t id() const { return idx; }
|
||||
void wait_for_search_finished();
|
||||
usize id() const { return idx; }
|
||||
|
||||
LargePagePtr<Search::Worker> worker;
|
||||
std::function<void()> jobFunc;
|
||||
@@ -102,7 +101,7 @@ class Thread {
|
||||
private:
|
||||
std::mutex mutex;
|
||||
std::condition_variable cv;
|
||||
size_t idx, idxInNuma, totalNuma, nthreads;
|
||||
usize idx, idxInNuma, totalNuma, nthreads;
|
||||
bool exit = false, searching = true; // Set before starting std::thread
|
||||
NativeThread stdThread;
|
||||
NumaReplicatedAccessToken numaAccessToken;
|
||||
@@ -132,26 +131,26 @@ class ThreadPool {
|
||||
ThreadPool& operator=(const ThreadPool&) = delete;
|
||||
ThreadPool& operator=(ThreadPool&&) = delete;
|
||||
|
||||
void start_thinking(const OptionsMap&, Position&, StateListPtr&, Search::LimitsType);
|
||||
void run_on_thread(size_t threadId, std::function<void()> f);
|
||||
void wait_on_thread(size_t threadId);
|
||||
size_t num_threads() const;
|
||||
void clear();
|
||||
void set(const NumaConfig& numaConfig,
|
||||
Search::SharedState,
|
||||
const Search::SearchManager::UpdateContext&);
|
||||
void start_thinking(const OptionsMap&, Position&, StateListPtr&, Search::LimitsType);
|
||||
void run_on_thread(usize threadId, std::function<void()> f);
|
||||
void wait_on_thread(usize threadId);
|
||||
usize num_threads() const;
|
||||
void clear();
|
||||
void set(const NumaConfig& numaConfig,
|
||||
Search::SharedState,
|
||||
const Search::SearchManager::UpdateContext&);
|
||||
|
||||
Search::SearchManager* main_manager();
|
||||
Thread* main_thread() const { return threads.front().get(); }
|
||||
uint64_t nodes_searched() const;
|
||||
uint64_t tb_hits() const;
|
||||
u64 nodes_searched() const;
|
||||
u64 tb_hits() const;
|
||||
Thread* get_best_thread() const;
|
||||
void start_searching();
|
||||
void wait_for_search_finished() const;
|
||||
|
||||
std::vector<size_t> get_bound_thread_to_numa_node() const;
|
||||
std::vector<size_t> get_bound_thread_count_by_numa_node() const;
|
||||
size_t numa_nodes() const;
|
||||
std::vector<usize> get_bound_thread_to_numa_node() const;
|
||||
std::vector<usize> get_bound_thread_count_by_numa_node() const;
|
||||
usize numa_nodes() const;
|
||||
|
||||
void ensure_network_replicated();
|
||||
|
||||
@@ -169,9 +168,9 @@ class ThreadPool {
|
||||
std::vector<std::unique_ptr<Thread>> threads;
|
||||
std::vector<NumaIndex> boundThreadToNumaNode;
|
||||
|
||||
uint64_t accumulate(std::atomic<uint64_t> Search::Worker::* member) const {
|
||||
u64 accumulate(std::atomic<u64> Search::Worker::* member) const {
|
||||
|
||||
uint64_t sum = 0;
|
||||
u64 sum = 0;
|
||||
for (auto&& th : threads)
|
||||
sum += (th->worker.get()->*member).load(std::memory_order_relaxed);
|
||||
return sum;
|
||||
|
||||
+3
-4
@@ -21,7 +21,6 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
#include "search.h"
|
||||
#include "ucioption.h"
|
||||
@@ -35,9 +34,9 @@ void TimeManagement::clear() {
|
||||
availableNodes = -1; // When in 'nodes as time' mode
|
||||
}
|
||||
|
||||
void TimeManagement::advance_nodes_time(std::int64_t nodes) {
|
||||
void TimeManagement::advance_nodes_time(i64 nodes) {
|
||||
assert(useNodesTime);
|
||||
availableNodes = std::max(int64_t(0), availableNodes - nodes);
|
||||
availableNodes = std::max(i64(0), availableNodes - nodes);
|
||||
}
|
||||
|
||||
// Called at the beginning of the search and calculates
|
||||
@@ -83,7 +82,7 @@ void TimeManagement::init(Search::LimitsType& limits,
|
||||
|
||||
// These numbers are used where multiplications, divisions,
|
||||
// or comparisons with constants are involved.
|
||||
const int64_t scaleFactor = useNodesTime ? npmsec : 1;
|
||||
const i64 scaleFactor = useNodesTime ? npmsec : 1;
|
||||
const TimePoint scaledTime = limits.time[us] / scaleFactor;
|
||||
|
||||
// Maximum move horizon
|
||||
|
||||
+4
-5
@@ -19,14 +19,13 @@
|
||||
#ifndef TIMEMAN_H_INCLUDED
|
||||
#define TIMEMAN_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
namespace Stockfish {
|
||||
|
||||
class OptionsMap;
|
||||
enum Color : uint8_t;
|
||||
enum Color : u8;
|
||||
|
||||
namespace Search {
|
||||
struct LimitsType;
|
||||
@@ -51,15 +50,15 @@ class TimeManagement {
|
||||
TimePoint elapsed_time() const { return now() - startTime; };
|
||||
|
||||
void clear();
|
||||
void advance_nodes_time(std::int64_t nodes);
|
||||
void advance_nodes_time(i64 nodes);
|
||||
|
||||
private:
|
||||
TimePoint startTime;
|
||||
TimePoint optimumTime;
|
||||
TimePoint maximumTime;
|
||||
|
||||
std::int64_t availableNodes = -1; // When in 'nodes as time' mode
|
||||
bool useNodesTime = false; // True if we are in 'nodes as time' mode
|
||||
i64 availableNodes = -1; // When in 'nodes as time' mode
|
||||
bool useNodesTime = false; // True if we are in 'nodes as time' mode
|
||||
};
|
||||
|
||||
} // namespace Stockfish
|
||||
|
||||
+39
-40
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
@@ -53,12 +52,12 @@ namespace Stockfish {
|
||||
// externally, so we offset the internal depth by DEPTH_NONE.
|
||||
//
|
||||
// Pv, bound and generation are packed in a single byte.
|
||||
static constexpr uint8_t GENERATION_BITS = 5;
|
||||
static constexpr uint8_t GENERATION_MASK = (1 << GENERATION_BITS) - 1;
|
||||
static constexpr uint8_t BOUND_SHIFT = GENERATION_BITS;
|
||||
static constexpr uint8_t BOUND_MASK = 0b11 << BOUND_SHIFT;
|
||||
static constexpr uint8_t PV_SHIFT = BOUND_SHIFT + 2;
|
||||
static constexpr uint8_t PV_MASK = 1 << PV_SHIFT;
|
||||
static constexpr u8 GENERATION_BITS = 5;
|
||||
static constexpr u8 GENERATION_MASK = (1 << GENERATION_BITS) - 1;
|
||||
static constexpr u8 BOUND_SHIFT = GENERATION_BITS;
|
||||
static constexpr u8 BOUND_MASK = 0b11 << BOUND_SHIFT;
|
||||
static constexpr u8 PV_SHIFT = BOUND_SHIFT + 2;
|
||||
static constexpr u8 PV_MASK = 1 << PV_SHIFT;
|
||||
|
||||
struct TTEntry {
|
||||
|
||||
@@ -73,43 +72,43 @@ struct TTEntry {
|
||||
}
|
||||
|
||||
bool is_occupied() const { return bool(depth8); };
|
||||
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t curr_generation);
|
||||
uint8_t relative_age(const uint8_t curr_generation) const;
|
||||
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, u8 curr_generation);
|
||||
u8 relative_age(const u8 curr_generation) const;
|
||||
|
||||
private:
|
||||
friend class TranspositionTable;
|
||||
friend struct TTWriter;
|
||||
|
||||
uint16_t key16;
|
||||
uint8_t depth8;
|
||||
uint8_t genBound8;
|
||||
Move move16;
|
||||
int16_t value16;
|
||||
int16_t eval16;
|
||||
u16 key16;
|
||||
u8 depth8;
|
||||
u8 genBound8;
|
||||
Move move16;
|
||||
i16 value16;
|
||||
i16 eval16;
|
||||
};
|
||||
|
||||
// Populates the TTEntry with a new node's data, possibly
|
||||
// overwriting an old position. The update is non-atomic and can be racy.
|
||||
void TTEntry::save(
|
||||
Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t curr_generation) {
|
||||
Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, u8 curr_generation) {
|
||||
|
||||
// Preserve the old ttmove if we don't have a new one
|
||||
if (m || uint16_t(k) != key16)
|
||||
if (m || u16(k) != key16)
|
||||
move16 = m;
|
||||
|
||||
// Overwrite less valuable entries (cheapest checks first)
|
||||
if (b == BOUND_EXACT || uint16_t(k) != key16 || d - DEPTH_NONE + 2 * pv > depth8 - 4
|
||||
if (b == BOUND_EXACT || u16(k) != key16 || d - DEPTH_NONE + 2 * pv > depth8 - 4
|
||||
|| relative_age(curr_generation))
|
||||
{
|
||||
assert(d > DEPTH_NONE);
|
||||
assert(d - DEPTH_NONE < 256);
|
||||
assert(curr_generation <= GENERATION_MASK); // TT::new_search() plays nice
|
||||
|
||||
key16 = uint16_t(k);
|
||||
depth8 = uint8_t(d - DEPTH_NONE);
|
||||
genBound8 = uint8_t(curr_generation | b << BOUND_SHIFT | uint8_t(pv) << PV_SHIFT);
|
||||
value16 = int16_t(v);
|
||||
eval16 = int16_t(ev);
|
||||
key16 = u16(k);
|
||||
depth8 = u8(d - DEPTH_NONE);
|
||||
genBound8 = u8(curr_generation | b << BOUND_SHIFT | u8(pv) << PV_SHIFT);
|
||||
value16 = i16(v);
|
||||
eval16 = i16(ev);
|
||||
}
|
||||
// Secondary aging. Important for elementary mate finding.
|
||||
// (*Scaler) Secondary aging on entries relevant to singular extensions
|
||||
@@ -125,7 +124,7 @@ void TTEntry::save(
|
||||
}
|
||||
|
||||
|
||||
uint8_t TTEntry::relative_age(const uint8_t curr_generation) const {
|
||||
u8 TTEntry::relative_age(const u8 curr_generation) const {
|
||||
// Returns this entry's age. We count generations like clocks count hours,
|
||||
// i.e. we require 0 - 1 == 31. Unsigned subtraction guarantees the required
|
||||
// borrowing regardless of the upper pv/bound bits.
|
||||
@@ -138,7 +137,7 @@ TTWriter::TTWriter(TTEntry* tte) :
|
||||
entry(tte) {}
|
||||
|
||||
void TTWriter::write(
|
||||
Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t curr_generation) {
|
||||
Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, u8 curr_generation) {
|
||||
entry->save(k, v, pv, b, d, m, ev, curr_generation);
|
||||
}
|
||||
|
||||
@@ -165,11 +164,11 @@ static_assert(sizeof(Cluster) == 32, "Suboptimal Cluster size");
|
||||
// Sets the size of the transposition table,
|
||||
// measured in megabytes. Transposition table consists
|
||||
// of clusters and each cluster consists of ClusterSize number of TTEntry.
|
||||
void TranspositionTable::resize(size_t mbSize, ThreadPool& threads) {
|
||||
void TranspositionTable::resize(usize mbSize, ThreadPool& threads) {
|
||||
aligned_large_pages_free(table);
|
||||
|
||||
clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster);
|
||||
size_t ttBytes = clusterCount * sizeof(Cluster);
|
||||
clusterCount = mbSize * 1024 * 1024 / sizeof(Cluster);
|
||||
usize ttBytes = clusterCount * sizeof(Cluster);
|
||||
|
||||
// Request 1GB pages if we'd get at least eight per NUMA node, to avoid
|
||||
// memory oversubscription
|
||||
@@ -190,36 +189,36 @@ void TranspositionTable::resize(size_t mbSize, ThreadPool& threads) {
|
||||
// Initializes the entire transposition table to zero,
|
||||
// in a multi-threaded way.
|
||||
void TranspositionTable::clear(ThreadPool& threads) {
|
||||
generation8 = 0;
|
||||
const size_t threadCount = threads.num_threads();
|
||||
generation8 = 0;
|
||||
const usize threadCount = threads.num_threads();
|
||||
|
||||
std::vector<size_t> threadToNuma = threads.get_bound_thread_to_numa_node();
|
||||
std::vector<usize> threadToNuma = threads.get_bound_thread_to_numa_node();
|
||||
|
||||
std::vector<size_t> order(threadCount);
|
||||
std::vector<usize> order(threadCount);
|
||||
std::iota(order.begin(), order.end(), 0);
|
||||
|
||||
// To promote good NUMA distribution (esp. with huge pages), we permute threads so that
|
||||
// all threads in a NUMA node clear a contiguous region of the TT.
|
||||
if (threadToNuma.size() == threadCount)
|
||||
{
|
||||
std::stable_sort(order.begin(), order.end(), [&threadToNuma](size_t t1, size_t t2) {
|
||||
std::stable_sort(order.begin(), order.end(), [&threadToNuma](usize t1, usize t2) {
|
||||
return threadToNuma.at(t1) < threadToNuma.at(t2);
|
||||
});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
for (usize i = 0; i < threadCount; ++i)
|
||||
{
|
||||
threads.run_on_thread(order[i], [this, i, threadCount]() {
|
||||
// Each thread will zero its part of the hash table
|
||||
const size_t stride = clusterCount / threadCount;
|
||||
const size_t start = stride * i;
|
||||
const size_t len = i + 1 != threadCount ? stride : clusterCount - start;
|
||||
const usize stride = clusterCount / threadCount;
|
||||
const usize start = stride * i;
|
||||
const usize len = i + 1 != threadCount ? stride : clusterCount - start;
|
||||
|
||||
std::memset(&table[start], 0, len * sizeof(Cluster));
|
||||
});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < threadCount; ++i)
|
||||
for (usize i = 0; i < threadCount; ++i)
|
||||
threads.wait_on_thread(i);
|
||||
}
|
||||
|
||||
@@ -245,7 +244,7 @@ void TranspositionTable::new_search() {
|
||||
}
|
||||
|
||||
|
||||
uint8_t TranspositionTable::generation() const { return generation8; }
|
||||
u8 TranspositionTable::generation() const { return generation8; }
|
||||
|
||||
|
||||
// Looks up the current position in the transposition table.
|
||||
@@ -255,7 +254,7 @@ uint8_t TranspositionTable::generation() const { return generation8; }
|
||||
std::tuple<bool, TTData, TTWriter> TranspositionTable::probe(const Key key) const {
|
||||
|
||||
TTEntry* const tte = first_entry(key);
|
||||
const uint16_t key16 = uint16_t(key); // Use the low 16 bits as key inside the cluster
|
||||
const u16 key16 = u16(key); // Use the low 16 bits as key inside the cluster
|
||||
|
||||
for (int i = 0; i < ClusterSize; ++i)
|
||||
if (tte[i].key16 == key16)
|
||||
|
||||
@@ -19,10 +19,9 @@
|
||||
#ifndef TT_H_INCLUDED
|
||||
#define TT_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
|
||||
#include "misc.h"
|
||||
#include "memory.h"
|
||||
#include "types.h"
|
||||
|
||||
@@ -67,7 +66,7 @@ struct TTData {
|
||||
// for chess reasons, we may decide the new data is less important than the old.
|
||||
struct TTWriter {
|
||||
public:
|
||||
void write(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8);
|
||||
void write(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, u8 generation8);
|
||||
void penalize(int penalty); // decrement stored depth by the penalty
|
||||
|
||||
private:
|
||||
@@ -82,12 +81,12 @@ class TranspositionTable {
|
||||
public:
|
||||
~TranspositionTable() { aligned_large_pages_free(table); }
|
||||
|
||||
void resize(size_t mbSize, ThreadPool& threads); // Set TT size in MiB
|
||||
void clear(ThreadPool& threads); // Re-initialize memory, multithreaded
|
||||
void resize(usize mbSize, ThreadPool& threads); // Set TT size in MiB
|
||||
void clear(ThreadPool& threads); // Re-initialize memory, multithreaded
|
||||
|
||||
void
|
||||
new_search(); // This must be called at the beginning of each root search to track entry aging
|
||||
uint8_t generation() const; // The current age, used when writing new data to the TT
|
||||
u8 generation() const; // The current age, used when writing new data to the TT
|
||||
// Approximate what fraction of entries (permille) have been written to during this root search
|
||||
int hashfull(int maxAge = 0) const;
|
||||
|
||||
@@ -102,10 +101,10 @@ class TranspositionTable {
|
||||
private:
|
||||
friend struct TTEntry;
|
||||
|
||||
size_t clusterCount;
|
||||
usize clusterCount;
|
||||
Cluster* table = nullptr;
|
||||
|
||||
uint8_t generation8 = 0;
|
||||
u8 generation8 = 0;
|
||||
};
|
||||
|
||||
} // namespace Stockfish
|
||||
|
||||
+21
-23
@@ -110,19 +110,19 @@ constexpr bool Is64Bit = true;
|
||||
constexpr bool Is64Bit = false;
|
||||
#endif
|
||||
|
||||
using Key = uint64_t;
|
||||
using Bitboard = uint64_t;
|
||||
using Key = u64;
|
||||
using Bitboard = u64;
|
||||
|
||||
constexpr int MAX_MOVES = 256;
|
||||
constexpr int MAX_PLY = 246;
|
||||
|
||||
enum Color : uint8_t {
|
||||
enum Color : u8 {
|
||||
WHITE,
|
||||
BLACK,
|
||||
COLOR_NB = 2
|
||||
};
|
||||
|
||||
enum CastlingRights : uint8_t {
|
||||
enum CastlingRights : u8 {
|
||||
NO_CASTLING,
|
||||
WHITE_OO,
|
||||
WHITE_OOO = WHITE_OO << 1,
|
||||
@@ -138,7 +138,7 @@ enum CastlingRights : uint8_t {
|
||||
CASTLING_RIGHT_NB = 16
|
||||
};
|
||||
|
||||
enum Bound : uint8_t {
|
||||
enum Bound : u8 {
|
||||
BOUND_NONE,
|
||||
BOUND_UPPER,
|
||||
BOUND_LOWER,
|
||||
@@ -201,13 +201,13 @@ constexpr Value QueenValue = 2538;
|
||||
|
||||
|
||||
// clang-format off
|
||||
enum PieceType : std::uint8_t {
|
||||
enum PieceType : u8 {
|
||||
NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING,
|
||||
ALL_PIECES = 0,
|
||||
PIECE_TYPE_NB = 8
|
||||
};
|
||||
|
||||
enum Piece : std::uint8_t {
|
||||
enum Piece : u8 {
|
||||
NO_PIECE,
|
||||
W_PAWN = PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
|
||||
B_PAWN = PAWN + 8, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
|
||||
@@ -238,7 +238,7 @@ constexpr Depth DEPTH_UNSEARCHED = -2;
|
||||
constexpr Depth DEPTH_NONE = -3;
|
||||
|
||||
// clang-format off
|
||||
enum Square : uint8_t {
|
||||
enum Square : u8 {
|
||||
SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1,
|
||||
SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2,
|
||||
SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3,
|
||||
@@ -254,7 +254,7 @@ enum Square : uint8_t {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
enum Direction : int8_t {
|
||||
enum Direction : i8 {
|
||||
NORTH = 8,
|
||||
EAST = 1,
|
||||
SOUTH = -NORTH,
|
||||
@@ -266,7 +266,7 @@ enum Direction : int8_t {
|
||||
NORTH_WEST = NORTH + WEST
|
||||
};
|
||||
|
||||
enum File : uint8_t {
|
||||
enum File : u8 {
|
||||
FILE_A,
|
||||
FILE_B,
|
||||
FILE_C,
|
||||
@@ -278,7 +278,7 @@ enum File : uint8_t {
|
||||
FILE_NB
|
||||
};
|
||||
|
||||
enum Rank : uint8_t {
|
||||
enum Rank : u8 {
|
||||
RANK_1,
|
||||
RANK_2,
|
||||
RANK_3,
|
||||
@@ -310,10 +310,10 @@ struct DirtyThreat {
|
||||
static constexpr int PcOffset = 20;
|
||||
|
||||
DirtyThreat() { /* don't initialize data */ }
|
||||
DirtyThreat(uint32_t raw) :
|
||||
DirtyThreat(u32 raw) :
|
||||
data(raw) {}
|
||||
DirtyThreat(Piece pc, Piece threatened_pc, Square pc_sq, Square threatened_sq, bool add) {
|
||||
data = (uint32_t(add) << 31) | (pc << PcOffset) | (threatened_pc << ThreatenedPcOffset)
|
||||
data = (u32(add) << 31) | (pc << PcOffset) | (threatened_pc << ThreatenedPcOffset)
|
||||
| (threatened_sq << ThreatenedSqOffset) | (pc_sq << PcSqOffset);
|
||||
}
|
||||
|
||||
@@ -322,10 +322,10 @@ struct DirtyThreat {
|
||||
Square threatened_sq() const { return static_cast<Square>(data >> ThreatenedSqOffset & 0xff); }
|
||||
Square pc_sq() const { return static_cast<Square>(data >> PcSqOffset & 0xff); }
|
||||
bool add() const { return data >> 31; }
|
||||
uint32_t raw() const { return data; }
|
||||
u32 raw() const { return data; }
|
||||
|
||||
private:
|
||||
uint32_t data;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
// A piece can be involved in at most 8 outgoing attacks and 16 incoming attacks.
|
||||
@@ -410,12 +410,10 @@ constexpr Direction pawn_push(Color c) { return c == WHITE ? NORTH : SOUTH; }
|
||||
|
||||
|
||||
// Based on a congruential pseudo-random number generator
|
||||
constexpr Key make_key(uint64_t seed) {
|
||||
return seed * 6364136223846793005ULL + 1442695040888963407ULL;
|
||||
}
|
||||
constexpr Key make_key(u64 seed) { return seed * 6364136223846793005ULL + 1442695040888963407ULL; }
|
||||
|
||||
|
||||
enum MoveType : uint16_t {
|
||||
enum MoveType : u16 {
|
||||
NORMAL,
|
||||
PROMOTION = 1 << 14,
|
||||
EN_PASSANT = 2 << 14,
|
||||
@@ -437,7 +435,7 @@ enum MoveType : uint16_t {
|
||||
class Move {
|
||||
public:
|
||||
Move() = default;
|
||||
constexpr explicit Move(std::uint16_t d) :
|
||||
constexpr explicit Move(u16 d) :
|
||||
data(d) {}
|
||||
|
||||
constexpr Move(Square from, Square to) :
|
||||
@@ -476,17 +474,17 @@ class Move {
|
||||
|
||||
constexpr explicit operator bool() const { return data != 0; }
|
||||
|
||||
constexpr std::uint16_t raw() const { return data; }
|
||||
constexpr u16 raw() const { return data; }
|
||||
|
||||
struct MoveHash {
|
||||
std::size_t operator()(const Move& m) const { return make_key(m.data); }
|
||||
usize operator()(const Move& m) const { return make_key(m.data); }
|
||||
};
|
||||
|
||||
static constexpr int FromSqShift = 6;
|
||||
static constexpr int ToSqShift = 0;
|
||||
|
||||
protected:
|
||||
std::uint16_t data;
|
||||
u16 data;
|
||||
};
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
|
||||
+5
-6
@@ -21,7 +21,6 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
@@ -226,8 +225,8 @@ void UCIEngine::go(std::istringstream& is) {
|
||||
|
||||
void UCIEngine::bench(std::istream& args) {
|
||||
std::string token;
|
||||
uint64_t num, nodes = 0, cnt = 1;
|
||||
uint64_t nodesSearched = 0;
|
||||
u64 num, nodes = 0, cnt = 1;
|
||||
u64 nodesSearched = 0;
|
||||
const auto& options = engine.get_options();
|
||||
|
||||
engine.set_on_update_full([&](const auto& i) {
|
||||
@@ -298,8 +297,8 @@ void UCIEngine::benchmark(std::istream& args) {
|
||||
static constexpr int NUM_WARMUP_POSITIONS = 3;
|
||||
|
||||
std::string token;
|
||||
uint64_t nodes = 0, cnt = 1;
|
||||
uint64_t nodesSearched = 0;
|
||||
u64 nodes = 0, cnt = 1;
|
||||
u64 nodesSearched = 0;
|
||||
|
||||
engine.set_on_update_full([&](const Engine::InfoFull& i) { nodesSearched = i.nodes; });
|
||||
|
||||
@@ -456,7 +455,7 @@ void UCIEngine::setoption(std::istringstream& is) {
|
||||
engine.get_options().setoption(is);
|
||||
}
|
||||
|
||||
std::uint64_t UCIEngine::perft(const Search::LimitsType& limits) {
|
||||
u64 UCIEngine::perft(const Search::LimitsType& limits) {
|
||||
auto nodes = engine.perft(engine.fen(), limits.perft, engine.get_options()["UCI_Chess960"]);
|
||||
sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
|
||||
return nodes;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#ifndef UCI_H_INCLUDED
|
||||
#define UCI_H_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -33,7 +32,7 @@ namespace Stockfish {
|
||||
class Position;
|
||||
class Move;
|
||||
class Score;
|
||||
enum Square : uint8_t;
|
||||
enum Square : u8;
|
||||
using Value = int;
|
||||
|
||||
constexpr auto StartFEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
|
||||
@@ -62,12 +61,12 @@ class UCIEngine {
|
||||
|
||||
static void print_info_string(std::string_view str);
|
||||
|
||||
void go(std::istringstream& is);
|
||||
void bench(std::istream& args);
|
||||
void benchmark(std::istream& args);
|
||||
void position(std::istringstream& is);
|
||||
void setoption(std::istringstream& is);
|
||||
std::uint64_t perft(const Search::LimitsType&);
|
||||
void go(std::istringstream& is);
|
||||
void bench(std::istream& args);
|
||||
void benchmark(std::istream& args);
|
||||
void position(std::istringstream& is);
|
||||
void setoption(std::istringstream& is);
|
||||
u64 perft(const Search::LimitsType&);
|
||||
|
||||
static void on_update_no_moves(const Engine::InfoShort& info);
|
||||
static void on_update_full(const Engine::InfoFull& info, bool showWDL);
|
||||
|
||||
+3
-3
@@ -68,7 +68,7 @@ const Option& OptionsMap::operator[](const std::string& name) const {
|
||||
void OptionsMap::add(const std::string& name, const Option& option) {
|
||||
if (!options_map.count(name))
|
||||
{
|
||||
static size_t insert_order = 0;
|
||||
static usize insert_order = 0;
|
||||
|
||||
options_map[name] = option;
|
||||
|
||||
@@ -83,7 +83,7 @@ void OptionsMap::add(const std::string& name, const Option& option) {
|
||||
}
|
||||
|
||||
|
||||
std::size_t OptionsMap::count(const std::string& name) const { return options_map.count(name); }
|
||||
usize OptionsMap::count(const std::string& name) const { return options_map.count(name); }
|
||||
|
||||
Option::Option(const OptionsMap* map) :
|
||||
parent(map) {}
|
||||
@@ -185,7 +185,7 @@ Option& Option::operator=(const std::string& v) {
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const OptionsMap& om) {
|
||||
for (size_t idx = 0; idx < om.options_map.size(); ++idx)
|
||||
for (usize idx = 0; idx < om.options_map.size(); ++idx)
|
||||
for (const auto& it : om.options_map)
|
||||
if (it.second.idx == idx)
|
||||
{
|
||||
|
||||
+4
-3
@@ -19,13 +19,14 @@
|
||||
#ifndef UCIOPTION_H_INCLUDED
|
||||
#define UCIOPTION_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
namespace Stockfish {
|
||||
// Define a custom comparator, because the UCI options should be case-insensitive
|
||||
struct CaseInsensitiveLess {
|
||||
@@ -64,7 +65,7 @@ class Option {
|
||||
|
||||
std::string defaultValue, currentValue, type;
|
||||
int min, max;
|
||||
size_t idx;
|
||||
usize idx;
|
||||
OnChange on_change;
|
||||
const OptionsMap* parent = nullptr;
|
||||
};
|
||||
@@ -87,7 +88,7 @@ class OptionsMap {
|
||||
|
||||
void add(const std::string&, const Option& option);
|
||||
|
||||
std::size_t count(const std::string&) const;
|
||||
usize count(const std::string&) const;
|
||||
|
||||
private:
|
||||
friend class Engine;
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
#include <unistd.h>
|
||||
|
||||
// Must be kept in sync with patch_x86_slice.sh
|
||||
extern const volatile uint64_t gUniversalNNUEOffset = 0xCAFE0FF5E70FF5E7ULL;
|
||||
extern const volatile uint64_t gUniversalNNUESize = 0xCAFE512ECAFE512EULL;
|
||||
extern const volatile Stockfish::u64 gUniversalNNUEOffset = 0xCAFE0FF5E70FF5E7ULL;
|
||||
extern const volatile Stockfish::u64 gUniversalNNUESize = 0xCAFE512ECAFE512EULL;
|
||||
|
||||
static const unsigned char* map_embedded_nnue() {
|
||||
char path[PATH_MAX];
|
||||
uint32_t len = sizeof(path);
|
||||
char path[PATH_MAX];
|
||||
Stockfish::u32 len = sizeof(path);
|
||||
if (_NSGetExecutablePath(path, &len) != 0)
|
||||
return nullptr;
|
||||
|
||||
@@ -51,9 +51,9 @@ static const unsigned char* map_embedded_nnue() {
|
||||
return nullptr;
|
||||
|
||||
// Align down to page size for mmap
|
||||
const uint64_t pageSize = uint64_t(sysconf(_SC_PAGESIZE));
|
||||
const uint64_t base = gUniversalNNUEOffset & ~(pageSize - 1);
|
||||
const uint64_t pad = gUniversalNNUEOffset - base;
|
||||
const Stockfish::u64 pageSize = Stockfish::u64(sysconf(_SC_PAGESIZE));
|
||||
const Stockfish::u64 base = gUniversalNNUEOffset & ~(pageSize - 1);
|
||||
const Stockfish::u64 pad = gUniversalNNUEOffset - base;
|
||||
|
||||
void* p =
|
||||
mmap(nullptr, size_t(gUniversalNNUESize + pad), PROT_READ, MAP_PRIVATE, fd, off_t(base));
|
||||
|
||||
Reference in New Issue
Block a user