mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-21 09:37:16 +08:00
Allow TT entries with key16==0 to be fetched
Fix the issue where a TT entry with key16==0 would always be reported
as a miss. Instead, we'll use depth8 to detect whether the TT entry is
occupied. In order to do that, we'll change DEPTH_OFFSET to -7
(depth8==0) to distinguish between an unoccupied entry and the
otherwise lowest possible depth, i.e., DEPTH_NONE (depth8==1).
To prevent a performance regression, we'll reorder the TT entry fields
by the access order of TranspositionTable::probe(). Memory in general
works fastest when accessed in sequential order. We'll also match the
store order in TTEntry::save() with the entry field order, and
re-order the 'if-or' expressions in TTEntry::save() from the cheapest
to the most expensive.
Finally, as we now have a proper TT entry occupancy test, we'll fix a
minor corner case with hashfull reporting. To reproduce:
- Use a big hash
- Either:
a. Start 31 very quick searches (this wraparounds generation to 0); or
b. Force generation of the first search to 0.
- go depth infinite
Before the fix, hashfull would incorrectly report nearly full hash
immediately after the search start, since
TranspositionTable::hashfull() used to consider only the entry
generation and not whether the entry was actually occupied.
STC:
LLR: 2.95 (-2.94,2.94) {-0.25,1.25}
Total: 36848 W: 4091 L: 3898 D: 28859
Ptnml(0-2): 158, 2996, 11972, 3091, 207
https://tests.stockfishchess.org/tests/view/5f3f98d5dc02a01a0c2881f7
LTC:
LLR: 2.95 (-2.94,2.94) {0.25,1.25}
Total: 32280 W: 1828 L: 1653 D: 28799
Ptnml(0-2): 34, 1428, 13051, 1583, 44
https://tests.stockfishchess.org/tests/view/5f3fe77a87a5c3c63d8f5332
closes https://github.com/official-stockfish/Stockfish/pull/3048
Bench: 3760677
This commit is contained in:
committed by
Joost VandeVondele
parent
701b2427bd
commit
f7b3f0e842
21
src/tt.cpp
21
src/tt.cpp
@@ -37,18 +37,19 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev)
|
|||||||
if (m || (uint16_t)k != key16)
|
if (m || (uint16_t)k != key16)
|
||||||
move16 = (uint16_t)m;
|
move16 = (uint16_t)m;
|
||||||
|
|
||||||
// Overwrite less valuable entries
|
// Overwrite less valuable entries (cheapest checks first)
|
||||||
if ((uint16_t)k != key16
|
if (b == BOUND_EXACT
|
||||||
|| d - DEPTH_OFFSET > depth8 - 4
|
|| (uint16_t)k != key16
|
||||||
|| b == BOUND_EXACT)
|
|| d - DEPTH_OFFSET > depth8 - 4)
|
||||||
{
|
{
|
||||||
assert(d >= DEPTH_OFFSET);
|
assert(d > DEPTH_OFFSET);
|
||||||
|
assert(d < 256 + DEPTH_OFFSET);
|
||||||
|
|
||||||
key16 = (uint16_t)k;
|
key16 = (uint16_t)k;
|
||||||
|
depth8 = (uint8_t)(d - DEPTH_OFFSET);
|
||||||
|
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
|
||||||
value16 = (int16_t)v;
|
value16 = (int16_t)v;
|
||||||
eval16 = (int16_t)ev;
|
eval16 = (int16_t)ev;
|
||||||
genBound8 = (uint8_t)(TT.generation8 | uint8_t(pv) << 2 | b);
|
|
||||||
depth8 = (uint8_t)(d - DEPTH_OFFSET);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,11 +120,11 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const {
|
|||||||
const uint16_t key16 = (uint16_t)key; // Use the low 16 bits as key inside the cluster
|
const uint16_t key16 = (uint16_t)key; // Use the low 16 bits as key inside the cluster
|
||||||
|
|
||||||
for (int i = 0; i < ClusterSize; ++i)
|
for (int i = 0; i < ClusterSize; ++i)
|
||||||
if (!tte[i].key16 || tte[i].key16 == key16)
|
if (tte[i].key16 == key16 || !tte[i].depth8)
|
||||||
{
|
{
|
||||||
tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & 0x7)); // Refresh
|
tte[i].genBound8 = uint8_t(generation8 | (tte[i].genBound8 & 0x7)); // Refresh
|
||||||
|
|
||||||
return found = (bool)tte[i].key16, &tte[i];
|
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
|
||||||
@@ -149,7 +150,7 @@ int TranspositionTable::hashfull() const {
|
|||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
for (int i = 0; i < 1000; ++i)
|
for (int i = 0; i < 1000; ++i)
|
||||||
for (int j = 0; j < ClusterSize; ++j)
|
for (int j = 0; j < ClusterSize; ++j)
|
||||||
cnt += (table[i].entry[j].genBound8 & 0xF8) == generation8;
|
cnt += table[i].entry[j].depth8 && (table[i].entry[j].genBound8 & 0xF8) == generation8;
|
||||||
|
|
||||||
return cnt / ClusterSize;
|
return cnt / ClusterSize;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/tt.h
12
src/tt.h
@@ -25,13 +25,13 @@
|
|||||||
/// TTEntry struct is the 10 bytes transposition table entry, defined as below:
|
/// TTEntry struct is the 10 bytes transposition table entry, defined as below:
|
||||||
///
|
///
|
||||||
/// key 16 bit
|
/// key 16 bit
|
||||||
/// move 16 bit
|
/// depth 8 bit
|
||||||
/// value 16 bit
|
|
||||||
/// eval value 16 bit
|
|
||||||
/// generation 5 bit
|
/// generation 5 bit
|
||||||
/// pv node 1 bit
|
/// pv node 1 bit
|
||||||
/// bound type 2 bit
|
/// bound type 2 bit
|
||||||
/// depth 8 bit
|
/// move 16 bit
|
||||||
|
/// value 16 bit
|
||||||
|
/// eval value 16 bit
|
||||||
|
|
||||||
struct TTEntry {
|
struct TTEntry {
|
||||||
|
|
||||||
@@ -47,11 +47,11 @@ private:
|
|||||||
friend class TranspositionTable;
|
friend class TranspositionTable;
|
||||||
|
|
||||||
uint16_t key16;
|
uint16_t key16;
|
||||||
|
uint8_t depth8;
|
||||||
|
uint8_t genBound8;
|
||||||
uint16_t move16;
|
uint16_t move16;
|
||||||
int16_t value16;
|
int16_t value16;
|
||||||
int16_t eval16;
|
int16_t eval16;
|
||||||
uint8_t genBound8;
|
|
||||||
uint8_t depth8;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -232,7 +232,8 @@ enum : int {
|
|||||||
DEPTH_QS_RECAPTURES = -5,
|
DEPTH_QS_RECAPTURES = -5,
|
||||||
|
|
||||||
DEPTH_NONE = -6,
|
DEPTH_NONE = -6,
|
||||||
DEPTH_OFFSET = DEPTH_NONE
|
|
||||||
|
DEPTH_OFFSET = -7 // value used only for TT entry occupancy check
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Square : int {
|
enum Square : int {
|
||||||
|
|||||||
Reference in New Issue
Block a user