Skip to content

Commit d5be763

Browse files
mdouzefacebook-github-bot
authored andcommitted
Enable dynamic dispatch build on Windows
Summary: Attempt to enable FAISS dynamic dispatch (DD) mode on Windows/MSVC. Changes: - CMakeLists.txt: Remove if(NOT WIN32) guard from DD section, add MSVC per-file SIMD flags (/arch:AVX2, /arch:AVX512, /bigobj) alongside existing GCC/Clang flags - build-pull-request.yml: Add windows-x86_64-DD-cmake job that runs immediately (no dependency on linux-x86_64-cmake), builds with MSVC and FAISS_OPT_LEVEL=dd, runs C++ tests and Python tests This diff is expected to fail on Windows due to MSVC requiring explicit template specialization declarations (C++ §17.8.3) which GCC/Clang don't enforce. The CI failure will surface the exact errors to guide the fix. Differential Revision: D101649751
1 parent 9d56749 commit d5be763

11 files changed

Lines changed: 108 additions & 38 deletions

.github/workflows/build-pull-request.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,47 @@ jobs:
170170
fetch-tags: true
171171
- name: Build and Package (conda)
172172
uses: ./.github/actions/build_conda
173+
windows-x86_64-DD-cmake:
174+
name: Windows x86_64 Dynamic Dispatch (cmake)
175+
runs-on: windows-2022
176+
steps:
177+
- name: Checkout
178+
uses: actions/checkout@v4
179+
- name: Setup miniconda
180+
uses: conda-incubator/setup-miniconda@v3
181+
with:
182+
python-version: '3.12'
183+
miniforge-version: latest
184+
channels: conda-forge
185+
- name: Install dependencies
186+
shell: pwsh
187+
run: |
188+
conda install -y -q cmake swig "numpy>=2.0,<3.0" scipy pytest gflags setuptools
189+
conda install -y -q mkl=2024.2.2 mkl-devel=2024.2.2
190+
- name: Build
191+
shell: pwsh
192+
run: |
193+
cmake -B build -T v143 -A x64 -G "Visual Studio 17 2022" `
194+
-DBUILD_TESTING=ON `
195+
-DBUILD_SHARED_LIBS=ON `
196+
-DFAISS_ENABLE_GPU=OFF `
197+
-DFAISS_OPT_LEVEL=dd `
198+
-DFAISS_ENABLE_PYTHON=OFF `
199+
-DFAISS_ENABLE_C_API=ON `
200+
-DBLA_VENDOR=Intel10_64_dyn `
201+
-DCMAKE_BUILD_TYPE=Release `
202+
.
203+
# Add faiss.dll and dependency DLLs to PATH for GoogleTest discovery
204+
$env:PATH = "$PWD\build\faiss\Release;$env:CONDA_PREFIX\Library\bin;$env:PATH"
205+
cmake --build build --config Release -j $env:NUMBER_OF_PROCESSORS
206+
- name: C++ tests
207+
shell: pwsh
208+
run: |
209+
# Copy faiss.dll next to the test executable so it can be found
210+
Copy-Item build\faiss\Release\faiss.dll build\tests\Release\
211+
$env:PATH = "$env:CONDA_PREFIX\Library\bin;$env:PATH"
212+
cd build
213+
ctest --output-on-failure -C Release
173214
windows-x86_64-conda:
174215
name: Windows x86_64 (conda)
175216
needs: linux-x86_64-cmake

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ endif()
115115
include(CTest)
116116
if(BUILD_TESTING)
117117
add_subdirectory(tests)
118-
add_subdirectory(perf_tests)
118+
if(NOT WIN32)
119+
add_subdirectory(perf_tests)
120+
endif()
119121
if(FAISS_ENABLE_GPU)
120122
if(FAISS_ENABLE_ROCM)
121123
add_subdirectory(faiss/gpu/test)

faiss/CMakeLists.txt

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -453,16 +453,16 @@ target_compile_definitions(faiss_sve PRIVATE COMPILE_SIMD_ARM_NEON COMPILE_SIMD_
453453
if(FAISS_OPT_LEVEL STREQUAL "dd")
454454
# Add SIMD source files to main faiss target for DD builds
455455
target_sources(faiss PRIVATE ${FAISS_SIMD_SRC})
456-
if(NOT WIN32)
457-
target_compile_definitions(faiss PRIVATE FAISS_ENABLE_DD)
458-
# Architecture-specific SIMD definitions for Dynamic Dispatch
459-
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64|AMD64)")
460-
target_compile_definitions(faiss PRIVATE
461-
COMPILE_SIMD_AVX2 COMPILE_SIMD_AVX512 COMPILE_SIMD_AVX512_SPR)
456+
target_compile_definitions(faiss PRIVATE FAISS_ENABLE_DD)
457+
# Architecture-specific SIMD definitions for Dynamic Dispatch
458+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64|amd64|AMD64)")
459+
target_compile_definitions(faiss PRIVATE
460+
COMPILE_SIMD_AVX2 COMPILE_SIMD_AVX512 COMPILE_SIMD_AVX512_SPR)
461+
if(NOT WIN32)
462462
# Baseline flags for common files (prevents auto-vectorization)
463463
target_compile_options(faiss PRIVATE
464464
$<$<COMPILE_LANGUAGE:CXX>:-mpopcnt -msse4 -mno-avx -mno-avx2>)
465-
# Per-file SIMD flags
465+
# Per-file SIMD flags (GCC/Clang)
466466
set_source_files_properties(${FAISS_SIMD_AVX2_SRC}
467467
TARGET_DIRECTORY faiss
468468
PROPERTIES COMPILE_OPTIONS "-mavx2;-mfma;-mf16c;-mpopcnt"
@@ -472,15 +472,26 @@ if(FAISS_OPT_LEVEL STREQUAL "dd")
472472
PROPERTIES COMPILE_OPTIONS
473473
"-mavx512f;-mavx512cd;-mavx512vl;-mavx512dq;-mavx512bw;-mfma;-mf16c;-mpopcnt"
474474
)
475-
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64|arm64|ARM64)")
476-
# ARM NEON is always available on aarch64, no special compiler flags needed
477-
target_compile_definitions(faiss PRIVATE COMPILE_SIMD_ARM_NEON COMPILE_SIMD_ARM_SVE)
478-
# Per-file SVE flags (NEON needs no flags on aarch64)
479-
set_source_files_properties(${FAISS_SIMD_SVE_SRC}
475+
else()
476+
# Per-file SIMD flags (MSVC)
477+
add_compile_options(/bigobj)
478+
set_source_files_properties(${FAISS_SIMD_AVX2_SRC}
479+
TARGET_DIRECTORY faiss
480+
PROPERTIES COMPILE_OPTIONS "/arch:AVX2"
481+
)
482+
set_source_files_properties(${FAISS_SIMD_AVX512_SRC}
480483
TARGET_DIRECTORY faiss
481-
PROPERTIES COMPILE_OPTIONS "-march=armv8.2-a+sve"
484+
PROPERTIES COMPILE_OPTIONS "/arch:AVX512"
482485
)
483486
endif()
487+
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64|arm64|ARM64)")
488+
# ARM NEON is always available on aarch64, no special compiler flags needed
489+
target_compile_definitions(faiss PRIVATE COMPILE_SIMD_ARM_NEON COMPILE_SIMD_ARM_SVE)
490+
# Per-file SVE flags (NEON needs no flags on aarch64)
491+
set_source_files_properties(${FAISS_SIMD_SVE_SRC}
492+
TARGET_DIRECTORY faiss
493+
PROPERTIES COMPILE_OPTIONS "-march=armv8.2-a+sve"
494+
)
484495
endif()
485496
endif()
486497

faiss/utils/distances_fused/avx512.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ void kernel(
7878
const float* const __restrict xd_0 = x + i * DIM;
7979

8080
// prefetch the next point
81-
_mm_prefetch(xd_0 + DIM * sizeof(float), _MM_HINT_NTA);
81+
_mm_prefetch((char*)(xd_0 + DIM * sizeof(float)), _MM_HINT_NTA);
8282

8383
// load a single point from x
8484
// load -2 * value
@@ -262,10 +262,10 @@ void exhaustive_L2sqr_fused_cmax(
262262
}
263263
}
264264

265-
const size_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
265+
const idx_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
266266
// the main loop.
267267
#pragma omp parallel for schedule(dynamic)
268-
for (size_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
268+
for (idx_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
269269
kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
270270
x, y, y_transposed.data(), ny, res, y_norms, i);
271271
}

tests/CMakeLists.txt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ set(FAISS_TEST_SRC
1010
test_ivfpq_indexing.cpp
1111
test_lowlevel_ivf.cpp
1212
test_ivf_index.cpp
13-
test_merge.cpp
1413
test_omp_threads.cpp
15-
test_ondisk_ivf.cpp
1614
test_pairs_decoding.cpp
1715
test_params_override.cpp
1816
test_pq_encoding.cpp
@@ -31,7 +29,6 @@ set(FAISS_TEST_SRC
3129
test_partitioning.cpp
3230
test_fastscan_perf.cpp
3331
test_pqfs_unaligned.cpp
34-
test_disable_pq_sdc_tables.cpp
3532
test_common_ivf_empty_index.cpp
3633
test_callback.cpp
3734
test_utils.cpp
@@ -49,6 +46,15 @@ set(FAISS_TEST_SRC
4946
test_fast_scan_distance_to_code.cpp
5047
)
5148

49+
# Tests that use POSIX APIs (pthread, mkstemp, unistd.h) not available on Windows
50+
if(NOT WIN32)
51+
list(APPEND FAISS_TEST_SRC
52+
test_merge.cpp
53+
test_ondisk_ivf.cpp
54+
test_disable_pq_sdc_tables.cpp
55+
)
56+
endif()
57+
5258
if(FAISS_ENABLE_SVS)
5359
list(APPEND FAISS_TEST_SRC test_svs.cpp)
5460
endif()
@@ -138,4 +144,10 @@ target_link_libraries(faiss_test PRIVATE
138144

139145
# Defines `gtest_discover_tests()`.
140146
include(GoogleTest)
141-
gtest_discover_tests(faiss_test)
147+
if(WIN32)
148+
# On Windows, defer test discovery to ctest time (PRE_TEST) instead of
149+
# build time (POST_BUILD) because faiss.dll is not in PATH during build.
150+
gtest_discover_tests(faiss_test DISCOVERY_MODE PRE_TEST)
151+
else()
152+
gtest_discover_tests(faiss_test)
153+
endif()

tests/test_fastscan_perf.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <gtest/gtest.h>
99

10+
#include <chrono>
1011
#include <cstddef>
1112
#include <cstdint>
1213
#include <memory>

tests/test_mmap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ std::vector<uint8_t> make_binary_data(
4646
size_t seed) {
4747
std::vector<uint8_t> database(n * d);
4848
std::mt19937 rng(seed);
49-
std::uniform_int_distribution<uint8_t> distrib(0, 255);
49+
std::uniform_int_distribution<int> distrib(0, 255);
5050

5151
for (size_t i = 0; i < n * d; i++) {
5252
database[i] = distrib(rng);

tests/test_pq_code_distance.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ void test(
5151

5252
// rng
5353
std::minstd_rand rng(123);
54-
std::uniform_int_distribution<uint8_t> u(0, 255);
54+
std::uniform_int_distribution<int> u(0, 255);
5555
std::uniform_real_distribution<float> uf(0, 1);
5656

5757
// initialize lookup
@@ -65,10 +65,10 @@ void test(
6565
#pragma omp parallel
6666
{
6767
std::minstd_rand rng0(123);
68-
std::uniform_int_distribution<uint8_t> u1(0, 255);
68+
std::uniform_int_distribution<int> u1(0, 255);
6969

7070
#pragma omp for schedule(guided)
71-
for (size_t i = 0; i < codes.size(); i++) {
71+
for (int64_t i = 0; i < (int64_t)codes.size(); i++) {
7272
codes[i] = u1(rng0);
7373
}
7474
}
@@ -77,7 +77,7 @@ void test(
7777
std::vector<float> resultsRef(n, 0);
7878
for (size_t k = 0; k < 10; k++) {
7979
#pragma omp parallel for schedule(guided)
80-
for (size_t i = 0; i < n; i++) {
80+
for (int64_t i = 0; i < (int64_t)n; i++) {
8181
resultsRef[i] = faiss::PQCodeDistance<
8282
faiss::PQDecoder8,
8383
faiss::SIMDLevel::NONE>::
@@ -93,7 +93,7 @@ void test(
9393
const auto startingTimepoint = std::chrono::steady_clock::now();
9494
for (size_t k = 0; k < 1000; k++) {
9595
#pragma omp parallel for schedule(guided)
96-
for (size_t i = 0; i < n; i++) {
96+
for (int64_t i = 0; i < (int64_t)n; i++) {
9797
resultsScalar1x[i] = faiss::PQCodeDistance<
9898
faiss::PQDecoder8,
9999
faiss::SIMDLevel::NONE>::
@@ -118,7 +118,7 @@ void test(
118118
const auto startingTimepoint = std::chrono::steady_clock::now();
119119
for (size_t k = 0; k < 1000; k++) {
120120
#pragma omp parallel for schedule(guided)
121-
for (size_t i = 0; i < n; i += 4) {
121+
for (int64_t i = 0; i < (int64_t)n; i += 4) {
122122
faiss::PQCodeDistance<
123123
faiss::PQDecoder8,
124124
faiss::SIMDLevel::NONE>::
@@ -151,7 +151,7 @@ void test(
151151
const auto startingTimepoint = std::chrono::steady_clock::now();
152152
for (size_t k = 0; k < 1000; k++) {
153153
#pragma omp parallel for schedule(guided)
154-
for (size_t i = 0; i < n; i++) {
154+
for (int64_t i = 0; i < (int64_t)n; i++) {
155155
resultsDispatched1x[i] = faiss::pq_code_distance_single(
156156
subq, 8, lookup.data(), codes.data() + subq * i);
157157
}
@@ -170,7 +170,7 @@ void test(
170170
const auto startingTimepoint = std::chrono::steady_clock::now();
171171
for (size_t k = 0; k < 1000; k++) {
172172
#pragma omp parallel for schedule(guided)
173-
for (size_t i = 0; i < n; i += 4) {
173+
for (int64_t i = 0; i < (int64_t)n; i += 4) {
174174
faiss::pq_code_distance_four(
175175
subq,
176176
8,

tests/test_pqfs_unaligned.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ TEST(FastScanUnaligned, TestUnalignedCodesAccess) {
5959
#endif
6060
std::random_device rd;
6161
std::mt19937 gen(rd());
62-
std::uniform_int_distribution<uint8_t> dist(
63-
std::numeric_limits<uint8_t>::min(),
64-
std::numeric_limits<uint8_t>::max());
62+
std::uniform_int_distribution<int> dist(0, 255);
6563

6664
std::vector<uint8_t> aligned_buffer =
6765
create_aligned_buffer(code_size, alignment);

tests/test_scalar_quantizer.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <cmath>
1111
#include <memory>
12+
#include <random>
1213
#include <vector>
1314

1415
#include <faiss/IndexFlat.h>
@@ -110,12 +111,14 @@ TEST(TestSQ0bit, CoarseOnlySearch) {
110111
int nq = 10;
111112
int k = 5;
112113

114+
std::mt19937 rng(42);
115+
std::uniform_real_distribution<float> distrib(0.0f, 1.0f);
113116
std::vector<float> xb(nb * d), xq(nq * d);
114117
for (int i = 0; i < nb * d; i++) {
115-
xb[i] = drand48();
118+
xb[i] = distrib(rng);
116119
}
117120
for (int i = 0; i < nq * d; i++) {
118-
xq[i] = drand48();
121+
xq[i] = distrib(rng);
119122
}
120123

121124
faiss::IndexFlatL2 quantizer(d);
@@ -180,12 +183,14 @@ TEST(TestSQ0bit, InnerProduct) {
180183
int nq = 5;
181184
int k = 3;
182185

186+
std::mt19937 rng2(43);
187+
std::uniform_real_distribution<float> distrib2(0.0f, 1.0f);
183188
std::vector<float> xb(nb * d), xq(nq * d);
184189
for (int i = 0; i < nb * d; i++) {
185-
xb[i] = drand48();
190+
xb[i] = distrib2(rng2);
186191
}
187192
for (int i = 0; i < nq * d; i++) {
188-
xq[i] = drand48();
193+
xq[i] = distrib2(rng2);
189194
}
190195

191196
faiss::IndexFlatIP quantizer(d);

0 commit comments

Comments
 (0)