1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-29 16:23:09 +00:00

Document TT code more

Slight refactor of the TT code with the goal to make it easier to understand / tweak.

Passed Non-Regression STC:
https://tests.stockfishchess.org/tests/view/65d51e401d8e83c78bfdc427
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 56416 W: 14750 L: 14550 D: 27116
Ptnml(0-2): 227, 6386, 14796, 6558, 241

closes https://github.com/official-stockfish/Stockfish/pull/5061

No functional change
This commit is contained in:
Disservin 2024-02-20 22:47:26 +01:00 committed by Joost VandeVondele
parent f77eddfa2f
commit 0a3eb1d8fa
2 changed files with 38 additions and 20 deletions

View file

@ -19,6 +19,7 @@
#include "tt.h" #include "tt.h"
#include <cassert> #include <cassert>
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
@ -53,6 +54,18 @@ void TTEntry::save(
} }
uint8_t TTEntry::relative_age(const uint8_t generation8) const {
// Due to our packed storage format for generation and its cyclic
// nature we add GENERATION_CYCLE (256 is the modulus, plus what
// is needed to keep the unrelated lowest n bits from affecting
// the result) to calculate the entry age correctly even after
// generation8 overflows into the next cycle.
return (TranspositionTable::GENERATION_CYCLE + generation8 - genBound8)
& TranspositionTable::GENERATION_MASK;
}
// Sets the size of the transposition table, // Sets the size of the transposition table,
// measured in megabytes. Transposition table consists of a power of 2 number // measured in megabytes. Transposition table consists of a power of 2 number
// of clusters and each cluster consists of ClusterSize number of TTEntry. // of clusters and each cluster consists of ClusterSize number of TTEntry.
@ -111,24 +124,18 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
for (int i = 0; i < ClusterSize; ++i) for (int i = 0; i < ClusterSize; ++i)
if (tte[i].key16 == key16 || !tte[i].depth8) if (tte[i].key16 == key16 || !tte[i].depth8)
{ {
tte[i].genBound8 = constexpr uint8_t lowerBits = GENERATION_DELTA - 1;
uint8_t(generation8 | (tte[i].genBound8 & (GENERATION_DELTA - 1))); // Refresh
return found = bool(tte[i].depth8), &tte[i]; // Refresh with new generation, keeping the lower bits the same.
tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & lowerBits));
return found = bool(tte[i].depth8), &tte[i];
} }
// Find an entry to be replaced according to the replacement strategy // Find an entry to be replaced according to the replacement strategy
TTEntry* replace = tte; TTEntry* replace = tte;
for (int i = 1; i < ClusterSize; ++i) for (int i = 1; i < ClusterSize; ++i)
// Due to our packed storage format for generation and its cyclic if (replace->depth8 - replace->relative_age(generation8)
// nature we add GENERATION_CYCLE (256 is the modulus, plus what > tte[i].depth8 - tte[i].relative_age(generation8))
// is needed to keep the unrelated lowest n bits from affecting
// the result) to calculate the entry age correctly even after
// generation8 overflows into the next cycle.
if (replace->depth8
- ((GENERATION_CYCLE + generation8 - replace->genBound8) & GENERATION_MASK)
> tte[i].depth8
- ((GENERATION_CYCLE + generation8 - tte[i].genBound8) & GENERATION_MASK))
replace = &tte[i]; replace = &tte[i];
return found = false, replace; return found = false, replace;
@ -137,7 +144,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
// Returns an approximation of the hashtable // Returns an approximation of the hashtable
// occupation during a search. The hash is x permill full, as per UCI protocol. // occupation during a search. The hash is x permill full, as per UCI protocol.
// Only counts entries which match the current generation.
int TranspositionTable::hashfull() const { int TranspositionTable::hashfull() const {
int cnt = 0; int cnt = 0;

View file

@ -46,6 +46,8 @@ struct TTEntry {
bool is_pv() const { return bool(genBound8 & 0x4); } bool is_pv() const { return bool(genBound8 & 0x4); }
Bound bound() const { return Bound(genBound8 & 0x3); } Bound bound() const { return Bound(genBound8 & 0x3); }
void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8); void save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8);
// The returned age is a multiple of TranspositionTable::GENERATION_DELTA
uint8_t relative_age(const uint8_t generation8) const;
private: private:
friend class TranspositionTable; friend class TranspositionTable;
@ -76,16 +78,25 @@ class TranspositionTable {
static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size"); static_assert(sizeof(Cluster) == 32, "Unexpected Cluster size");
// Constants used to refresh the hash table periodically // Constants used to refresh the hash table periodically
static constexpr unsigned GENERATION_BITS = 3; // nb of bits reserved for other things
static constexpr int GENERATION_DELTA = // We have 8 bits available where the lowest 3 bits are
(1 << GENERATION_BITS); // increment for generation field // reserved for other things.
static constexpr int GENERATION_CYCLE = 255 + (1 << GENERATION_BITS); // cycle length static constexpr unsigned GENERATION_BITS = 3;
static constexpr int GENERATION_MASK = // increment for generation field
(0xFF << GENERATION_BITS) & 0xFF; // mask to pull out generation number static constexpr int GENERATION_DELTA = (1 << GENERATION_BITS);
// cycle length
static constexpr int GENERATION_CYCLE = 255 + GENERATION_DELTA;
// mask to pull out generation number
static constexpr int GENERATION_MASK = (0xFF << GENERATION_BITS) & 0xFF;
public: public:
~TranspositionTable() { aligned_large_pages_free(table); } ~TranspositionTable() { aligned_large_pages_free(table); }
void new_search() { generation8 += GENERATION_DELTA; } // Lower bits are used for other things
void new_search() {
// increment by delta to keep lower bits as is
generation8 += GENERATION_DELTA;
}
TTEntry* probe(const Key key, bool& found) const; TTEntry* probe(const Key key, bool& found) const;
int hashfull() const; int hashfull() const;
void resize(size_t mbSize, int threadCount); void resize(size_t mbSize, int threadCount);