mirror of
https://github.com/facebookresearch/faiss.git
synced 2026-10-12 02:13:36 +00:00
Summary: Pull Request resolved: https://github.com/facebookresearch/faiss/pull/5127 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. UPDATE: in fact, MSVC does not seem to require this. After fixing build scripts and a few classical Windows error, the C++ and python tests pass. Reviewed By: algoriddle Differential Revision: D101649751 fbshipit-source-id: 765ef8483d02652ce58625cd22baab8870acf718
112 lines
3.5 KiB
C++
112 lines
3.5 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
#include <faiss/IndexIVF.h>
|
|
#include <faiss/impl/fast_scan/fast_scan.h>
|
|
#include <faiss/utils/AlignedTable.h>
|
|
#include <faiss/utils/random.h>
|
|
|
|
/**
|
|
* This validates we can run fast scan with unaligned codes and get the same
|
|
* results as aligned codes. On modern CPUs, unaligned codes appear to have
|
|
* similar performance characteristics to aligned codes.
|
|
*/
|
|
|
|
namespace {
|
|
|
|
std::vector<uint8_t> create_aligned_buffer(size_t size, size_t alignment) {
|
|
// Allocate extra space for alignment adjustment
|
|
std::vector<uint8_t> buffer(size + alignment);
|
|
return buffer;
|
|
}
|
|
|
|
uint8_t* get_aligned_ptr(std::vector<uint8_t>& buffer, size_t alignment) {
|
|
uint8_t* new_ptr;
|
|
int ret = posix_memalign(
|
|
(void**)&new_ptr, alignment, buffer.size() * sizeof(uint8_t));
|
|
if (ret != 0) {
|
|
throw std::bad_alloc();
|
|
}
|
|
return new_ptr;
|
|
}
|
|
|
|
uint8_t* get_unaligned_ptr(std::vector<uint8_t>& buffer, size_t alignment) {
|
|
uint8_t* aligned = get_aligned_ptr(buffer, alignment);
|
|
// Return pointer that is off by 1 byte from alignment
|
|
return aligned + 1;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(FastScanUnaligned, TestUnalignedCodesAccess) {
|
|
constexpr size_t alignment = 32;
|
|
constexpr int nsq = 8;
|
|
size_t code_size;
|
|
#ifdef __AVX512F__
|
|
code_size = 512;
|
|
#else
|
|
code_size = 256;
|
|
#endif
|
|
std::random_device rd;
|
|
std::mt19937 gen(rd());
|
|
std::uniform_int_distribution<int> dist(0, 255);
|
|
|
|
std::vector<uint8_t> aligned_buffer =
|
|
create_aligned_buffer(code_size, alignment);
|
|
// unaligned_buffer itself is aligned but it's the buffer for the unaligned
|
|
// pointer.
|
|
std::vector<uint8_t> unaligned_buffer =
|
|
create_aligned_buffer(code_size, alignment);
|
|
|
|
uint8_t* codes_aligned = get_aligned_ptr(aligned_buffer, alignment);
|
|
uint8_t* codes_unaligned = get_unaligned_ptr(unaligned_buffer, alignment);
|
|
|
|
for (size_t i = 0; i < code_size; i++) {
|
|
uint8_t val = static_cast<uint8_t>(dist(gen));
|
|
codes_aligned[i] = val;
|
|
codes_unaligned[i] = val;
|
|
}
|
|
|
|
ASSERT_TRUE(faiss::is_aligned_pointer(codes_aligned));
|
|
ASSERT_FALSE(faiss::is_aligned_pointer(codes_unaligned));
|
|
|
|
constexpr int nq = 2;
|
|
std::vector<uint8_t> LUT_aligned_buffer =
|
|
create_aligned_buffer(nq * nsq * 16, alignment);
|
|
uint8_t* LUT = get_aligned_ptr(LUT_aligned_buffer, alignment);
|
|
|
|
for (size_t i = 0; i < nq * nsq * 16; i++) {
|
|
LUT[i] = static_cast<uint8_t>(dist(gen));
|
|
}
|
|
|
|
// result_size is a subset of code_size, to not run off the unaligned buffer
|
|
constexpr size_t result_size = 64;
|
|
std::vector<uint16_t> accu_aligned(nq * result_size);
|
|
std::vector<uint16_t> accu_unaligned(nq * result_size);
|
|
|
|
faiss::accumulate_to_mem(
|
|
nq, result_size, nsq, codes_aligned, LUT, accu_aligned.data());
|
|
|
|
faiss::accumulate_to_mem(
|
|
nq, result_size, nsq, codes_unaligned, LUT, accu_unaligned.data());
|
|
|
|
// They should be the same, because codes_unaligned gets set to the same
|
|
// values as aligned, it's just not aligned.
|
|
ASSERT_EQ(accu_aligned, accu_unaligned)
|
|
<< "Aligned and unaligned code paths should produce identical results";
|
|
|
|
posix_memalign_free(codes_aligned);
|
|
posix_memalign_free(codes_unaligned - 1);
|
|
posix_memalign_free(LUT);
|
|
}
|