Skip to content

Commit ab16c1e

Browse files
committed
build(ci): enable FORCE_AVX2 in CI and add DEGLIB_TARGET_AVX512 attribute for GCC/Clang
1 parent cd67a9f commit ab16c1e

9 files changed

Lines changed: 40 additions & 22 deletions

File tree

.github/workflows/cpp-ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
sudo apt-get install -y cmake g++
3232
3333
- name: Configure CMake
34-
run: cmake -B build -S cpp -DFORCE_AVX2=OFF -DENABLE_BENCHMARKS=OFF
34+
run: cmake -B build -S cpp -DFORCE_AVX2=ON -DENABLE_BENCHMARKS=OFF
3535

3636
- name: Build
3737
run: cmake --build build --config Release

cpp/CMakeLists.txt

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,31 @@ endif()
3434

3535
if (FORCE_AVX2)
3636
message(NOTICE "Compiling for avx2, ignoring native optimizations.")
37+
include(CheckCXXCompilerFlag)
3738

3839
# setup compiler flags
39-
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
40-
target_compile_options(compile-options INTERFACE -O3 -mavx2 -mfma -fpic -w -pthread -ftree-vectorize)
40+
if(MSVC)
41+
check_cxx_compiler_flag("/arch:AVX2" COMPILER_SUPPORTS_AVX2)
42+
if(COMPILER_SUPPORTS_AVX2)
43+
target_compile_options(compile-options INTERFACE /O2 /arch:AVX2 /W1 /EHsc)
44+
else()
45+
target_compile_options(compile-options INTERFACE /O2 /W1 /EHsc)
46+
endif()
47+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
48+
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
49+
if(COMPILER_SUPPORTS_AVX2)
50+
target_compile_options(compile-options INTERFACE -O3 -mavx2 -mfma -fpic -w -pthread -ftree-vectorize)
51+
else()
52+
target_compile_options(compile-options INTERFACE -O3 -fpic -w -pthread -ftree-vectorize)
53+
endif()
4154
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
42-
target_compile_options(compile-options INTERFACE -O2 -fpic)
43-
55+
target_compile_options(compile-options INTERFACE -O2 -fpic)
4456
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
57+
check_cxx_compiler_flag("-mavx2" COMPILER_SUPPORTS_AVX2)
58+
if(COMPILER_SUPPORTS_AVX2)
4559
target_compile_options(compile-options INTERFACE -mavx2 -mfma)
60+
endif()
4661
endif()
47-
elseif(MSVC)
48-
target_compile_options(
49-
compile-options
50-
INTERFACE /O2
51-
/arch:AVX2
52-
/W1
53-
/EHsc)
5462
else()
5563
message(WARNING "Unknown compiler for AVX2 Build: ${CMAKE_CXX_COMPILER_ID}")
5664
endif()

cpp/deglib/include/config.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,21 @@
66
#define DEGLIB_X86 1
77
#endif
88

9-
// Always include the x86 intrinsic headers so that SIMD code in the distance
10-
// headers compiles regardless of the target architecture flags.
9+
// Target attribute for AVX-512 functions on GCC/Clang
10+
#if defined(DEGLIB_X86) && (defined(__GNUC__) || defined(__clang__))
11+
#define DEGLIB_TARGET_AVX512 __attribute__((target("avx512f,avx512dq,fma")))
12+
#else
13+
#define DEGLIB_TARGET_AVX512
14+
#endif
15+
16+
// Architecture intrinsic headers
1117
#if defined(DEGLIB_X86)
1218
#ifdef _MSC_VER
1319
#include <intrin.h>
1420
#include <stdexcept>
1521
#else
1622
#include <x86intrin.h>
1723
#include <xmmintrin.h> // for _mm_prefetch
18-
#endif
19-
#if defined(__GNUC__) || defined(__clang__)
2024
#include <cpuid.h>
2125
#endif
2226
#endif

cpp/deglib/include/distance/fp32_ip.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ namespace deglib::distances::fp32_ip {
5454

5555
class InnerProductFloat16Ext_AVX512 {
5656
public:
57-
inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
57+
DEGLIB_TARGET_AVX512 inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
5858
return 1.f - ip_16ext(pVect1v, pVect2v, qty_ptr);
5959
}
6060

61-
inline static float ip_16ext(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
61+
DEGLIB_TARGET_AVX512 inline static float ip_16ext(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
6262
float *a = (float *) pVect1v;
6363
float *b = (float *) pVect2v;
6464
size_t size = *((size_t *) qty_ptr);
@@ -240,7 +240,7 @@ namespace deglib::distances::fp32_ip {
240240

241241
class InnerProductFloat16ExtResiduals_AVX512 {
242242
public:
243-
inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
243+
DEGLIB_TARGET_AVX512 inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
244244
size_t qty = *((size_t *) qty_ptr);
245245

246246
size_t qty16 = qty >> 4 << 4;

cpp/deglib/include/distance/fp32_l2.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ namespace deglib::distances::fp32_l2 {
5050

5151
class L2Float16Ext_AVX512 {
5252
public:
53-
inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr)
53+
DEGLIB_TARGET_AVX512 inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr)
5454
{
5555
float *a = (float *) pVect1v;
5656
float *b = (float *) pVect2v;
@@ -248,7 +248,7 @@ namespace deglib::distances::fp32_l2 {
248248

249249
class L2Float16ExtResiduals_AVX512 {
250250
public:
251-
inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
251+
DEGLIB_TARGET_AVX512 inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
252252
size_t qty = *((size_t *) qty_ptr);
253253

254254
size_t qty16 = qty >> 4 << 4;

cpp/deglib/include/distance/uint8_l2.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ namespace deglib::distances::uint8_l2 {
3636

3737
class L2Uint8Ext32_AVX512 {
3838
public:
39-
inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
39+
DEGLIB_TARGET_AVX512 inline static float compare(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
4040
size_t size = *((size_t *) qty_ptr);
4141
const unsigned char *a = (const unsigned char *) pVect1v;
4242
const unsigned char *b = (const unsigned char *) pVect2v;

cpp/test/src/regression/metric/test_innerproduct_regression.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ TEST(DeglibRegressionIP, MultiInstructionSetBenchmark)
1717
// Test each distance variant with its own performance thresholds
1818
// num_runs=50 extends the search measurement window to ~280ms per run,
1919
// reducing QPS noise from OS jitter and CPU power-state transitions.
20+
#if defined(DEGLIB_X86)
2021
if (deglib::cpu::has_avx512()) {
2122
run_regression_test("AVX512_16Ext", deglib::Metric::InnerProduct, 18000.0, 10.3, 0.774,
2223
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
@@ -32,6 +33,7 @@ TEST(DeglibRegressionIP, MultiInstructionSetBenchmark)
3233
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
3334
deglib::distances::fp32_ip::InnerProductFloat16Ext_SSE{}, 50);
3435
}
36+
#endif
3537
run_regression_test("Scalar", deglib::Metric::InnerProduct, 12000.0, 15.4, 0.78,
3638
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
3739
deglib::distances::fp32_ip::InnerProductFloat{}, 50);

cpp/test/src/regression/metric/test_l2_regression.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ TEST(DeglibRegressionL2, MultiInstructionSetBenchmark)
1717
// Test each distance variant with its own performance thresholds
1818
// num_runs=50 extends the search measurement window to ~130ms per run,
1919
// reducing QPS noise from OS jitter and CPU power-state transitions.
20+
#if defined(DEGLIB_X86)
2021
if (deglib::cpu::has_avx512()) {
2122
run_regression_test("AVX512_16Ext", deglib::Metric::L2, 38000.0, 6.1, 0.92,
2223
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
@@ -32,6 +33,7 @@ TEST(DeglibRegressionL2, MultiInstructionSetBenchmark)
3233
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
3334
deglib::distances::fp32_l2::L2Float16Ext_SSE{}, 100);
3435
}
36+
#endif
3537
run_regression_test("Scalar", deglib::Metric::L2, 28000.0, 9.3, 0.92,
3638
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
3739
deglib::distances::fp32_l2::L2Float{}, 100);

cpp/test/src/regression/metric/test_l2_uint8_regression.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ TEST(DeglibRegressionL2Uint8, MultiInstructionSetBenchmark)
1616
// Explicitly test each distance variant with its own performance thresholds
1717
// num_runs=50 extends the search measurement window to ~70ms per run,
1818
// reducing QPS noise from OS jitter and CPU power-state transitions.
19+
#if defined(DEGLIB_X86)
1920
if (deglib::cpu::has_avx512()) {
2021
run_regression_test("AVX512_Ext32", deglib::Metric::L2_Uint8, 73000.0, 4.7, 1,
2122
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
@@ -31,6 +32,7 @@ TEST(DeglibRegressionL2Uint8, MultiInstructionSetBenchmark)
3132
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
3233
deglib::distances::uint8_l2::L2Uint8Ext32_SSE{}, 100);
3334
}
35+
#endif
3436
run_regression_test("Scalar", deglib::Metric::L2_Uint8, 63000.0, 5.5, 1,
3537
base_data.data(), query_data.data(), base_count, query_count, dim, gt_data,
3638
deglib::distances::uint8_l2::L2Uint8{}, 100);

0 commit comments

Comments
 (0)