Line data Source code
1 : #include "transposition.hpp"
2 :
3 : #include "distributed.h"
4 : #include "dynamicConfig.hpp"
5 : #include "logging.hpp"
6 : #include "moveApply.hpp"
7 : #include "movePseudoLegal.hpp"
8 : #include "position.hpp"
9 : #include "searcher.hpp"
10 : #include "tools.hpp"
11 :
12 : namespace {
13 :
14 : template<class T> struct DeleteAligned {
15 : void operator()(T *ptr) const {
16 : if (ptr) std_aligned_free(ptr);
17 24 : }
18 : };
19 :
20 : uint64_t ttSize = 0;
21 : std::unique_ptr<TT::Entry[], DeleteAligned<TT::Entry>> table(nullptr);
22 :
23 : } // namespace
24 : namespace TT {
25 :
26 : GenerationType curGen = 0;
27 :
28 : #ifdef __linux__
29 : #include <sys/mman.h>
30 : #endif
31 :
32 24 : void initTable() {
33 24 : Logging::LogIt(Logging::logInfo) << "Init TT";
34 24 : Logging::LogIt(Logging::logInfo) << "Entry size " << sizeof(Entry);
35 48 : ttSize = powerFloor((SIZE_MULTIPLIER * DynamicConfig::ttSizeMb) / sizeof(Entry));
36 24 : assert(BB::countBit(ttSize) == 1); // a power of 2
37 24 : table.reset((Entry *)std_aligned_alloc(1024, ttSize * sizeof(Entry)));
38 48 : Logging::LogIt(Logging::logInfo) << "Size of TT " << ttSize * sizeof(Entry) / 1024 / 1024 << "Mb (" << ttSize << " entries)";
39 24 : clearTT();
40 24 : }
41 :
42 50 : void clearTT() {
43 50 : TT::curGen = 0;
44 50 : Logging::LogIt(Logging::logInfo) << "Now zeroing TT memory using " << DynamicConfig::threads << " threads";
45 53 : auto worker = [&](size_t begin, size_t end) { std::fill(&table[0] + begin, &table[0] + end, Entry()); };
46 50 : threadedWork(worker, DynamicConfig::threads, ttSize);
47 50 : Logging::LogIt(Logging::logInfo) << "... done ";
48 50 : }
49 :
50 33 : int hashFull() {
51 : unsigned int count = 0;
52 : const unsigned int samples = 1023 * 64;
53 2160609 : for (unsigned int k = 0; k < samples; ++k)
54 2160576 : if (table[(k * 67) % ttSize].h != nullHash) ++count;
55 33 : return static_cast<int>((count * 1000) / samples);
56 : }
57 :
58 208 : void age() {
59 208 : TT::curGen = static_cast<GenerationType>((TT::curGen + 1) % 8); // see Bound::B_gen
60 208 : }
61 :
62 12830637 : void prefetch(Hash h) {
63 12830637 : void *addr = (&table[h & (ttSize - 1)]);
64 : #if defined(__INTEL_COMPILER)
65 : __asm__("");
66 : #elif defined(_MSC_VER)
67 : _mm_prefetch((char *)addr, _MM_HINT_T0);
68 : #else
69 12830637 : __builtin_prefetch(addr);
70 : #endif
71 12830637 : }
72 :
73 : // will return true only if depth is enough
74 : // e.h is nullHash if the TT entry is not usable
75 6728628 : bool getEntry(Searcher &context, const Position &p, Hash h, DepthType d, Entry &e) {
76 6728628 : assert(h != nullHash);
77 6728628 : assert((h & (ttSize - 1)) == (h % ttSize));
78 6728628 : if (DynamicConfig::disableTT) return false;
79 : // update entry immediatly to avoid further race condition and invalidate it later if needed
80 6728628 : e = table[h & (ttSize - 1)];
81 : #ifdef DEBUG_HASH_ENTRY
82 : e._data1 = randomInt<uint32_t, 666>(0, UINT32_MAX);
83 : e._data2 = randomInt<uint32_t, 666>(0, UINT32_MAX);
84 : #endif
85 6728628 : if (e.h == nullHash) return false; //early exit
86 : if (
87 : #ifndef DEBUG_HASH_ENTRY
88 3921616 : ((e.h ^ e._data1 ^ e._data2) != Hash64to32(h)) ||
89 : #endif
90 1692728 : (isValidMove(e.m) && !isPseudoLegal(p, e.m))) {
91 : // move is filled, but wrong in this position, invalidate returned entry.
92 664064 : e.h = nullHash;
93 664064 : return false;
94 : }
95 :
96 3257552 : if (e.d >= d /*+ (e.b != B_exact)*/) {
97 : // valid entry only if depth is ok
98 : context.stats.incr(Stats::sid_tthits);
99 1823139 : return true;
100 : }
101 : else{
102 : return false;
103 : }
104 : }
105 :
106 : // always replace
107 5706276 : void setEntry(Searcher &context, Hash h, Move m, ScoreType s, ScoreType eval, Bound b, DepthType d, bool distribute) {
108 5706276 : assert(h != nullHash); // can really happen in fact ... but rarely
109 5706276 : if (DynamicConfig::disableTT) return;
110 : Entry e(h, m, s, eval, b, d);
111 5706276 : e.h ^= e._data1;
112 5706276 : e.h ^= e._data2;
113 : context.stats.incr(Stats::sid_ttInsert);
114 5706276 : table[h & (ttSize - 1)] = e; // always replace (favour leaf)
115 : // only update buffer for other process on main thread
116 : if (distribute) Distributed::setEntry(h, e);
117 : }
118 :
119 0 : void _setEntry(Hash h, const Entry &e) { table[h & (ttSize - 1)] = e; }
120 :
121 277 : void getPV(const Position &p, Searcher &context, PVList &pv) {
122 : TT::Entry e;
123 277 : array1d<Hash,MAX_PLY> hashStack = {nullHash};
124 277 : Position p2 = p;
125 : #ifdef WITH_NNUE
126 277 : NNUEEvaluator evaluator;
127 : p2.associateEvaluator(evaluator);
128 277 : p2.resetNNUEEvaluator(p2.evaluator());
129 : #endif
130 : bool stop = false;
131 2914 : for (int k = 0; k < MAX_PLY && !stop; ++k) {
132 2897 : if (!TT::getEntry(context, p2, computeHash(p2), 0, e)) break;
133 2737 : if (e.h != nullHash) {
134 2737 : hashStack[k] = computeHash(p2);
135 : if (!isValidMove(e.m)) break;
136 2637 : if (const MoveInfo moveInfo(p2,e.m); !applyMove(p2, moveInfo)) break;
137 2637 : pv.emplace_back(e.m);
138 2637 : const Hash h = computeHash(p2);
139 : // stop at first repetition
140 21084 : for (int i = k - 1; i >= 0; --i)
141 18464 : if (hashStack[i] == h) {
142 : stop = true;
143 : break;
144 : }
145 : }
146 : }
147 277 : }
148 :
149 11412552 : ScoreType createHashScore(ScoreType score, DepthType height) {
150 11412552 : if (isMatingScore(score))
151 9133 : score += height;
152 11403419 : else if (isMatedScore(score))
153 1094909 : score -= height;
154 : //else
155 : // score *= 0.999f;
156 11412552 : return score;
157 : }
158 :
159 1052279 : ScoreType adjustHashScore(ScoreType score, DepthType height) {
160 1052279 : if (isMatingScore(score))
161 4640 : score -= height;
162 1047639 : else if (isMatedScore(score))
163 509 : score += height;
164 : //else
165 : // score *= 0.999f;
166 1052279 : return score;
167 : }
168 :
169 : } // namespace TT
|