diff --git a/sql/vector_mhnsw.cc b/sql/vector_mhnsw.cc index c480c36c7e7ad..475bdf007ec9b 100644 --- a/sql/vector_mhnsw.cc +++ b/sql/vector_mhnsw.cc @@ -36,6 +36,22 @@ static constexpr float subdist_margin= 1.05f; static constexpr double subdist_stddev_threshold= 0.05; // 3σ, p>99.9% static constexpr ulonglong subdist_stddev_valid= 10000; // sufficient +/* Portable read prefetch, modeled after UNIV_PREFETCH_R. */ +#if defined(__GNUC__) || defined(__clang__) +# define MHNSW_PREFETCH_READ(addr) __builtin_prefetch((addr), 0, 3) +#elif defined(_MSC_VER) +# include +# if defined(_M_IX86) || defined(_M_X64) +# define MHNSW_PREFETCH_READ(addr) \ + _mm_prefetch(reinterpret_cast(addr), _MM_HINT_T0) +# elif defined(_M_ARM64) +# define MHNSW_PREFETCH_READ(addr) __prefetch(addr) +# endif +#endif +#ifndef MHNSW_PREFETCH_READ +# define MHNSW_PREFETCH_READ(addr) ((void) 0) +#endif + /* The class below can assume normal distribution and only collect M1 and M2, or go beyond that and collect M3 and M4 to account @@ -1347,6 +1363,18 @@ static int search_layer(MHNSW_param *p, const FVector *target, float threshold, if (res == 0xff) continue; + // A node and its vector share one allocation. Prefetch unseen nodes before + // computing distances so later loads can overlap with work on earlier ones. + for (size_t i= 0; i < 8; i++) + { + FVectorNode *link= links[i]; + if (!(res & (1 << i)) && link) + { + MHNSW_PREFETCH_READ(link); + MHNSW_PREFETCH_READ(reinterpret_cast(link) + 64); + } + } + for (size_t i= 0; i < 8; i++) { if (res & (1 << i))