Files
faiss/tests/CMakeLists.txt
T
lyang24 e6bd1d252c Add AVX512 VPOPCNT dynamic dispatch level (#5531)
Summary:
## What

  Split the existing VPOPCNTDQ RaBitQ and Hamming kernels from the full Sapphire Rapids SIMD level.

  DD builds now expose an `AVX512_VPOPCNT` capability for CPUs such as Ice Lake and Zen 4. The fallback chain is:

  `AVX512_SPR -> AVX512_VPOPCNT -> AVX512 -> AVX2 -> NONE`

  The ordinary static AVX512 target remains unchanged and contains no VPOPCNT instructions.

  ## Why

  The VPOPCNT kernels only require baseline AVX-512 plus `AVX512_VPOPCNTDQ`. Tying them to the SPR level unnecessarily excluded CPUs that support VPOPCNTDQ but not AVX512-FP16, notably Zen 4.

  ## Changes made while importing

  Two changes were needed on top of the pull request.

  **Feature detection read the wrong CPUID leaf.** `AVX512_VPOPCNTDQ` and `AVX512_VNNI` were read from leaf 1 ECX. Both live in leaf 7 subleaf 0 ECX, at bits 14 and 11. Leaf 1 ECX holds unrelated bits at those positions, so the new level was never selected on any CPU. Measured on an AMD Genoa host before the fix: the level reported as unavailable and detection returned `AVX512`. After the fix the same host reports `AVX512_VPOPCNT`.

  **The build definitions outside CMake were not updated.** The pull request renames three files. The other build description still named the old paths and had no entry for the new level, so the library did not build. This adds the level constant, its compiler flags, its `COMPILE_SIMD_AVX512_VPOPCNT` define, and the renamed paths.

**The new level was not registered in the compiled-level mask.** `compiled_simd_levels()` reports which levels a binary holds, and `FAISS_SIMD_LEVEL` walks down from the requested level until it finds one that is present. The new level had no entry, so the override always stepped past it to `AVX512` and printed that the level was not compiled in. This was reported by `test_dispatch_with_env_var` on the open-source dynamic-dispatch build.

  **The test helper inferred available levels from `/proc/cpuinfo`.** A CPU feature does not imply that a level is compiled into the build, so the helper listed a level the override then refused. It now asks `SIMDConfig::is_simd_level_available()`, which reports compiled and supported. That is a subset of compiled, so every level it returns is one the override accepts.

  The mask and helper names also follow the naming used in the parent diff, so `AVAILABLE_SIMD_LEVELS_BASE_WITH_VPOPCNT` and `with_simd_level_with_vpopcnt`.

Pull Request resolved: https://github.com/facebookresearch/faiss/pull/5531

Test Plan:
```
buck2 test fbcode//mode/opt -c faiss.dynamic_dispatch=true \
  fbcode//faiss/tests:test_simd_levels fbcode//faiss/tests:test_rabitq_simd
```
Result: all pass.

The build failures the imported version reported are cleared. All three configurations build:
```
buck2 build fbcode//mode/dev fbcode//faiss:faiss fbcode//faiss:faiss_no_multithreading fbcode//faiss:faiss_omp_mock
buck2 build fbcode//mode/opt -c faiss.dynamic_dispatch=true <same three targets>
buck2 build fbcode//mode/dev -c fbcode.arch=aarch64 <same three targets>
```

Detection on an AMD Genoa host, which has AVX512_VPOPCNTDQ and AVX512_BF16 but not AVX512_FP16:

| | before the CPUID fix | after |
| --- | --- | --- |
| detected level | `AVX512` | `AVX512_VPOPCNT` |
| `AVX512_VPOPCNT` available | 0 | 1 |
| `AVX512_SPR` available | 0 | 0 |

Reviewed By: alibeklfc

Differential Revision: D118969754

Pulled By: mnorris11

fbshipit-source-id: d1ca52b614829a3d4b322c9fecf0c004f2174dab
2026-09-10 09:32:36 -07:00

164 lines
4.8 KiB
CMake

# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
set(FAISS_TEST_SRC
test_binary_flat.cpp
test_dealloc_invlists.cpp
test_ivfpq_codec.cpp
test_ivfpq_indexing.cpp
test_lowlevel_ivf.cpp
test_ivf_index.cpp
test_omp_threads.cpp
test_pairs_decoding.cpp
test_params_override.cpp
test_pq_encoding.cpp
test_sliding_ivf.cpp
test_threaded_index.cpp
test_transfer_invlists.cpp
test_cppcontrib_sa_decode.cpp
test_cppcontrib_uintreader.cpp
test_simdlib.cpp
test_approx_topk.cpp
test_RCQ_cropping.cpp
test_heap.cpp
test_pq_code_distance.cpp
test_hnsw.cpp
test_NSG_compressed_graph.cpp
test_partitioning.cpp
test_fastscan_perf.cpp
test_pqfs_unaligned.cpp
test_common_ivf_empty_index.cpp
test_ivf_early_termination.cpp
test_callback.cpp
test_utils.cpp
test_hamming.cpp
test_zerocopy.cpp
test_scalar_quantizer.cpp
test_factory_tools.cpp
test_custom_result_handler.cpp
test_fastscan_filter.cpp
test_single_query_collect_handler.cpp
# These tests work in both static and DD modes (uniform SIMDConfig API)
test_distances_simd.cpp
test_simd_levels.cpp
test_fast_scan_distance_to_code.cpp
test_rabitq_fastscan.cpp
test_super_kmeans_foundations.cpp
)
# Tests that use POSIX APIs or have platform-specific issues on Windows
if(NOT WIN32)
list(APPEND FAISS_TEST_SRC
test_merge.cpp
test_ondisk_ivf.cpp
test_disable_pq_sdc_tables.cpp
test_mmap.cpp
)
endif()
if(FAISS_ENABLE_SVS)
list(APPEND FAISS_TEST_SRC test_svs.cpp)
endif()
# DD-only tests; x86-specific raw-intrinsic tests are added separately below.
if(FAISS_OPT_LEVEL STREQUAL "dd")
list(APPEND FAISS_TEST_SRC
test_distances_dispatch.cpp
test_simd_perf.cpp
)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64|AMD64)")
list(APPEND FAISS_TEST_SRC
test_rabitq_simd.cpp
test_rabitq_simd_vpopcnt.cpp
test_simd_levels_x86_avx2.cpp
test_simd_levels_x86_avx512.cpp
)
# Set SIMD compile flags per file
# test_simd_levels_x86_avx2.cpp and test_simd_levels_x86_avx512.cpp
# contain raw intrinsics and need their respective SIMD flags.
if(NOT WIN32)
set_source_files_properties(test_simd_levels_x86_avx2.cpp
PROPERTIES COMPILE_OPTIONS "-mavx2;-mfma;-mf16c;-mpopcnt"
)
set_source_files_properties(test_simd_levels_x86_avx512.cpp
PROPERTIES COMPILE_OPTIONS "-mavx2;-mfma;-mf16c;-mpopcnt;-mavx512f;-mavx512cd;-mavx512vl;-mavx512dq;-mavx512bw"
)
else()
# MSVC
set_source_files_properties(test_simd_levels_x86_avx2.cpp
PROPERTIES COMPILE_OPTIONS "/arch:AVX2"
)
set_source_files_properties(test_simd_levels_x86_avx512.cpp
PROPERTIES COMPILE_OPTIONS "/arch:AVX512"
)
endif()
endif()
endif()
add_executable(faiss_test ${FAISS_TEST_SRC})
if(FAISS_ENABLE_SVS)
target_compile_definitions(faiss_test PRIVATE FAISS_ENABLE_SVS FAISS_SVS_RUNTIME_VERSION=${FAISS_SVS_RUNTIME_VERSION})
endif()
include(../cmake/link_to_faiss_lib.cmake)
link_to_faiss_lib(faiss_test)
if (FAISS_ENABLE_PYTHON)
add_dependencies(faiss_test faiss_example_external_module)
endif()
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG 58d77fa8070e8cec2dc1ed015d66b454c8d78850 # release-1.12.1
OVERRIDE_FIND_PACKAGE)
set(BUILD_GMOCK CACHE BOOL OFF)
set(INSTALL_GTEST CACHE BOOL OFF)
FetchContent_MakeAvailable(googletest)
if(NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake
AND NOT EXISTS ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/GTestConfig.cmake)
file(
WRITE ${CMAKE_FIND_PACKAGE_REDIRECTS_DIR}/gtest-config.cmake
[=[
include(CMakeFindDependencyMacro)
find_dependency(googletest)
if(NOT TARGET GTest::GTest)
add_library(GTest::GTest INTERFACE IMPORTED)
target_link_libraries(GTest::GTest INTERFACE GTest::gtest)
endif()
if(NOT TARGET GTest::Main)
add_library(GTest::Main INTERFACE IMPORTED)
target_link_libraries(GTest::Main INTERFACE GTest::gtest_main)
endif()
]=])
endif()
find_package(OpenMP REQUIRED)
find_package(GTest CONFIG REQUIRED)
target_link_libraries(faiss_test PRIVATE
OpenMP::OpenMP_CXX
GTest::gtest_main
$<$<BOOL:${FAISS_ENABLE_ROCM}>:hip::host>
)
# Defines `gtest_discover_tests()`.
include(GoogleTest)
if(CMAKE_CROSSCOMPILING)
# Skip test discovery when cross-compiling: the binary cannot run on the
# host, so gtest_discover_tests() would fail. The build itself verifies
# that the binary compiles and links correctly.
elseif(WIN32)
# On Windows, defer test discovery to ctest time (PRE_TEST) instead of
# build time (POST_BUILD) because faiss.dll is not in PATH during build.
gtest_discover_tests(faiss_test DISCOVERY_MODE PRE_TEST)
else()
gtest_discover_tests(faiss_test)
endif()