Prefetch threat weight rows during append_changed_indices

Passed STC (first run):
https://tests.stockfishchess.org/tests/view/698030ee6362aee5c8a552c7
LLR: 2.96 (-2.94,2.94) <0.00,2.00>
Total: 120800 W: 31336 L: 30912 D: 58552
Ptnml(0-2): 330, 13084, 33172, 13460, 354

Passed LTC:
https://tests.stockfishchess.org/tests/view/6983946d473df9d1d24a916d
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 86850 W: 22352 L: 21951 D: 42547
Ptnml(0-2): 45, 8506, 25934, 8883, 57

Passed STC SMP (after changes made after opening the PR):
https://tests.stockfishchess.org/tests/view/6987b4c1b0f3ca5200aaf9da
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 84480 W: 21994 L: 21627 D: 40859
Ptnml(0-2): 98, 9378, 22932, 9723, 109

Passed STC (second run, as a sanity check made after changes made after opening the PR -- these changed, however, didn't change assembly code produced by the compiler):
https://tests.stockfishchess.org/tests/view/6987ad21b0f3ca5200aaf9c9
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 132192 W: 34526 L: 34083 D: 63583
Ptnml(0-2): 421, 14511, 35759, 15014, 391

GCC maps __builtin_prefetch locality=1 to PREFETCHT2 instruction, targeting L2
cache. To make things clear, added template-based approach as suggested by
Disservin.

PREFETCHT2 should be the appropriate choice for the 78 MB threat weight table:
avoids L1d pollution, parks data in L2 where it is promoted to L1d on actual
load.

With 200-500 cycle lead time from make_index, data has time to arrive in L2.

suggestions by Disservin and anematode included

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

No functional change
This commit is contained in:
Maxim Masiutin
2026-02-13 07:01:15 +01:00
committed by Joost VandeVondele
parent 99221e5ee6
commit 238ef05bb0
5 changed files with 108 additions and 38 deletions
+63 -2
View File
@@ -37,6 +37,10 @@
#include <type_traits>
#include <vector>
#if !defined(NO_PREFETCH) && (defined(_MSC_VER) || defined(__INTEL_COMPILER))
#include <immintrin.h>
#endif
#define stringify2(x) #x
#define stringify(x) stringify2(x)
@@ -46,10 +50,67 @@ std::string engine_version_info();
std::string engine_info(bool to_uci = false);
std::string compiler_info();
// Preloads the given address in L1/L2 cache. This is a non-blocking
// Prefetch hint enums for explicit call-site control.
enum class PrefetchRw {
READ,
WRITE
};
// NOTE: PrefetchLoc controls locality / cache level, not whether a prefetch
// is issued. In particular, PrefetchLoc::NONE maps to a non-temporal /
// lowest-locality prefetch (Intel: _MM_HINT_NTA, GCC/Clang: locality = 0)
// and therefore still performs a prefetch. To completely disable
// prefetching, define NO_PREFETCH so that prefetch() becomes a no-op.
enum class PrefetchLoc {
NONE, // Non-temporal / no cache locality (still issues a prefetch)
LOW, // Low locality (e.g. T2 / L2)
MODERATE, // Moderate locality (e.g. T1 / L1)
HIGH // High locality (e.g. T0 / closest cache)
};
// Preloads the given address into cache. This is a non-blocking
// function that doesn't stall the CPU waiting for data to be loaded from memory,
// which can be quite slow.
void prefetch(const void* addr);
#ifdef NO_PREFETCH
template<PrefetchRw RW = PrefetchRw::READ, PrefetchLoc LOC = PrefetchLoc::HIGH>
void prefetch(const void*) {}
#elif defined(_MSC_VER) || defined(__INTEL_COMPILER)
constexpr int get_intel_hint(PrefetchRw rw, PrefetchLoc loc) {
if (rw == PrefetchRw::WRITE)
{
#ifdef _MM_HINT_ET0
return _MM_HINT_ET0;
#else
// Fallback when write-prefetch hint is not available: use T0
return _MM_HINT_T0;
#endif
}
switch (loc)
{
case PrefetchLoc::NONE :
return _MM_HINT_NTA;
case PrefetchLoc::LOW :
return _MM_HINT_T2;
case PrefetchLoc::MODERATE :
return _MM_HINT_T1;
case PrefetchLoc::HIGH :
return _MM_HINT_T0;
default :
return _MM_HINT_T0;
}
}
template<PrefetchRw RW = PrefetchRw::READ, PrefetchLoc LOC = PrefetchLoc::HIGH>
void prefetch(const void* addr) {
_mm_prefetch(static_cast<const char*>(addr), get_intel_hint(RW, LOC));
}
#else
template<PrefetchRw RW = PrefetchRw::READ, PrefetchLoc LOC = PrefetchLoc::HIGH>
void prefetch(const void* addr) {
__builtin_prefetch(addr, static_cast<int>(RW), static_cast<int>(LOC));
}
#endif
void start_logger(const std::string& fname);