From f34ffd09b5183c577c655b9dd8e0232863343d35 Mon Sep 17 00:00:00 2001 From: Dmitry Razdoburdin <> Date: Mon, 14 Apr 2025 08:33:32 -0700 Subject: [PATCH 1/8] just add the YAML for arm --- .github/workflows/build-linux-arm.yml | 73 +++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/build-linux-arm.yml diff --git a/.github/workflows/build-linux-arm.yml b/.github/workflows/build-linux-arm.yml new file mode 100644 index 000000000..9179728cd --- /dev/null +++ b/.github/workflows/build-linux-arm.yml @@ -0,0 +1,73 @@ +# Copyright 2023 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Linux Build and Test on ARM + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +# This allows a subsequently queued workflow run to interrupt previous runs +concurrency: + group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' + cancel-in-progress: true + +jobs: + build: + name: ${{ matrix.cxx }}, ${{ matrix.build_type }} + runs-on: ubuntu-22.04-arm + strategy: + matrix: + build_type: [RelWithDebugInfo] + cxx: [g++-11, g++-12, clang++-15] + include: + - cxx: g++-11 + cc: gcc-11 + - cxx: g++-12 + cc: gcc-12 + - cxx: clang++-15 + cc: clang-15 + + steps: + - uses: actions/checkout@v4 + + - name: Configure build + working-directory: ${{ runner.temp }} + env: + CXX: ${{ matrix.cxx }} + CC: ${{ matrix.cc }} + TEMP_WORKSPACE: ${{ runner.temp }} + run: | + cmake -B${TEMP_WORKSPACE}/build -S${GITHUB_WORKSPACE} \ + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ + -DSVS_BUILD_BINARIES=YES \ + -DSVS_BUILD_TESTS=YES \ + -DSVS_BUILD_EXAMPLES=YES \ + -DSVS_EXPERIMENTAL_LEANVEC=YES \ + -DSVS_NO_AVX512=YES + + - name: Build Tests and Utilities + working-directory: ${{ runner.temp }}/build + run: make -j$(nproc) + + - name: Run tests + env: + CTEST_OUTPUT_ON_FAILURE: 1 + working-directory: ${{ runner.temp }}/build/tests + run: ctest -C ${{ matrix.build_type }} From f993102516fd287c987bc560440989eb037ad726 Mon Sep 17 00:00:00 2001 From: Dmitry Razdoburdin <> Date: Mon, 14 Apr 2025 08:41:15 -0700 Subject: [PATCH 2/8] modify the yaml to avoid unsupported flags --- .github/workflows/build-linux-arm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-linux-arm.yml b/.github/workflows/build-linux-arm.yml index 9179728cd..09ce975dd 100644 --- a/.github/workflows/build-linux-arm.yml +++ b/.github/workflows/build-linux-arm.yml @@ -60,7 +60,7 @@ jobs: -DSVS_BUILD_TESTS=YES \ -DSVS_BUILD_EXAMPLES=YES \ -DSVS_EXPERIMENTAL_LEANVEC=YES \ - -DSVS_NO_AVX512=YES + -DSVS_NO_AVX512=NO - name: Build Tests and Utilities working-directory: ${{ runner.temp }}/build From d4e63a430cf6ced830180b6ff496b6bec4b42f93 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 15 Apr 2025 08:16:41 +0000 Subject: [PATCH 3/8] fix some build errors for arm --- include/svs/core/distance/cosine.h | 6 +++++- include/svs/core/distance/euclidean.h | 7 ++++++- include/svs/core/distance/inner_product.h | 7 ++++++- include/svs/lib/spinlock.h | 9 ++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/svs/core/distance/cosine.h b/include/svs/core/distance/cosine.h index 53c9ec620..f00430756 100644 --- a/include/svs/core/distance/cosine.h +++ b/include/svs/core/distance/cosine.h @@ -18,7 +18,6 @@ // svs #include "svs/core/distance/distance_core.h" -#include "svs/core/distance/simd_utils.h" #include "svs/lib/saveload.h" #include "svs/lib/static.h" @@ -29,7 +28,12 @@ #include #include #include + +SVS_VALIDATE_BOOL_ENV(SVS_AVX512_F) +#if SVS_AVX512_F +#include "svs/core/distance/simd_utils.h" #include +#endif // SVS_AVX512_F namespace svs::distance { // Forward declare implementation to allow entry point to be near the top. diff --git a/include/svs/core/distance/euclidean.h b/include/svs/core/distance/euclidean.h index ee82df751..3b4d5d6de 100644 --- a/include/svs/core/distance/euclidean.h +++ b/include/svs/core/distance/euclidean.h @@ -18,7 +18,6 @@ // svs #include "svs/core/distance/distance_core.h" -#include "svs/core/distance/simd_utils.h" #include "svs/lib/float16.h" #include "svs/lib/preprocessor.h" #include "svs/lib/saveload.h" @@ -31,7 +30,13 @@ #include #include #include + +SVS_VALIDATE_BOOL_ENV(SVS_AVX512_F) +SVS_VALIDATE_BOOL_ENV(SVS_AVX2) +#if SVS_AVX512_F || SVS_AVX2 +#include "svs/core/distance/simd_utils.h" #include +#endif // SVS_AVX512_F || SVS_AVX2 // Implementation Notes regarding Intel(R) AVX Extentions // Top most entry in the bulleted list underneath each type pair is the preferred diff --git a/include/svs/core/distance/inner_product.h b/include/svs/core/distance/inner_product.h index 136c6bf9c..6496dabfa 100644 --- a/include/svs/core/distance/inner_product.h +++ b/include/svs/core/distance/inner_product.h @@ -18,7 +18,6 @@ // svs #include "svs/core/distance/distance_core.h" -#include "svs/core/distance/simd_utils.h" #include "svs/lib/float16.h" #include "svs/lib/preprocessor.h" #include "svs/lib/saveload.h" @@ -29,7 +28,13 @@ #include #include #include + +SVS_VALIDATE_BOOL_ENV(SVS_AVX512_F) +SVS_VALIDATE_BOOL_ENV(SVS_AVX2) +#if SVS_AVX512_F || SVS_AVX2 +#include "svs/core/distance/simd_utils.h" #include +#endif // SVS_AVX512_F || SVS_AVX2 namespace svs::distance { // Forward declare implementation to allow entry point to be near the top. diff --git a/include/svs/lib/spinlock.h b/include/svs/lib/spinlock.h index 865308c47..952c5101e 100644 --- a/include/svs/lib/spinlock.h +++ b/include/svs/lib/spinlock.h @@ -17,11 +17,18 @@ #pragma once #include +// #include // __cpp_inline_assembly namespace svs { namespace detail { -inline void pause() { __builtin_ia32_pause(); } +inline void pause() { + #if defined(__i386__) || defined(__x86_64__) + __builtin_ia32_pause(); + #elif defined(__aarch64__) + asm volatile ("yield" ::: "memory"); + #endif +} } // namespace detail /// From 62c1f8eaffb7c7fcde9a8575c5899510ed8bc2c8 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 15 Apr 2025 10:08:12 +0000 Subject: [PATCH 4/8] more fixes --- include/svs/lib/prefetch.h | 2 +- tests/svs/core/distances/simd_utils.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/svs/lib/prefetch.h b/include/svs/lib/prefetch.h index 8facc820a..0fd438ba6 100644 --- a/include/svs/lib/prefetch.h +++ b/include/svs/lib/prefetch.h @@ -33,7 +33,7 @@ template void prefetch_l0(const T* ptr) { } #else // Do nothing if prefetch is not-available. -template void prefetch_l0(const T* ptr) {} +template void prefetch_l0([[maybe_unused]] const T* ptr) {} #endif const size_t CACHELINE_BYTES = 64; diff --git a/tests/svs/core/distances/simd_utils.cpp b/tests/svs/core/distances/simd_utils.cpp index ebb4a6faa..8c562dd47 100644 --- a/tests/svs/core/distances/simd_utils.cpp +++ b/tests/svs/core/distances/simd_utils.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#if defined(__i386__) || defined(__x86_64__) + #include #include @@ -61,3 +63,5 @@ CATCH_TEST_CASE("Masks", "[distance]") { CATCH_REQUIRE(svs::create_mask<16>(svs::lib::MaybeStatic<100>()) == 0xF); CATCH_REQUIRE(svs::create_mask<16>(svs::lib::MaybeStatic<16>()) == 0xFFFF); } + +#endif // defined(__i386__) || defined(__x86_64__) From 1af21b054a48b9eebb29a2f36975fd7a95cb7c59 Mon Sep 17 00:00:00 2001 From: Dmitry Razdoburdin <> Date: Tue, 15 Apr 2025 07:45:30 -0700 Subject: [PATCH 5/8] remove confusing SVS_NO_AVX512 flag --- .github/workflows/build-linux-arm.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-linux-arm.yml b/.github/workflows/build-linux-arm.yml index 09ce975dd..e34edfa86 100644 --- a/.github/workflows/build-linux-arm.yml +++ b/.github/workflows/build-linux-arm.yml @@ -59,8 +59,7 @@ jobs: -DSVS_BUILD_BINARIES=YES \ -DSVS_BUILD_TESTS=YES \ -DSVS_BUILD_EXAMPLES=YES \ - -DSVS_EXPERIMENTAL_LEANVEC=YES \ - -DSVS_NO_AVX512=NO + -DSVS_EXPERIMENTAL_LEANVEC=YES - name: Build Tests and Utilities working-directory: ${{ runner.temp }}/build From e26732ddd71efae7480d3d08fc88bd362d825d26 Mon Sep 17 00:00:00 2001 From: Rafik Saliev Date: Tue, 15 Apr 2025 17:07:29 +0200 Subject: [PATCH 6/8] Fix svs::lib::allocator (#106) This PR fixes allocate/deallocate mismatch to resolve Valgrind memory checks errors. --- include/svs/lib/memory.h | 2 +- include/svs/lib/threads/threadlocal.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/svs/lib/memory.h b/include/svs/lib/memory.h index c79fff114..7f5539010 100644 --- a/include/svs/lib/memory.h +++ b/include/svs/lib/memory.h @@ -61,7 +61,7 @@ template struct Allocator { } constexpr void deallocate(value_type* ptr, size_t count) noexcept { - ::operator delete(ptr, count); + ::operator delete(static_cast(ptr), sizeof(T) * count, std::align_val_t(alignof(T))); } // Intercept zero-argument construction to do default initialization. diff --git a/include/svs/lib/threads/threadlocal.h b/include/svs/lib/threads/threadlocal.h index f6d399fb5..5fdebd25a 100644 --- a/include/svs/lib/threads/threadlocal.h +++ b/include/svs/lib/threads/threadlocal.h @@ -82,7 +82,8 @@ template struct AlignedAllocat } void deallocate(value_type* ptr, size_t count) noexcept { - ::operator delete(ptr, count, std::align_val_t{alignment}); + size_t bytes = alignment * lib::div_round_up(sizeof(T) * count, alignment); + ::operator delete(static_cast(ptr), bytes, std::align_val_t{alignment}); } }; From 5a7da989d0d0e5a603851069c90465498845a78b Mon Sep 17 00:00:00 2001 From: yuejiaointel <108152493+yuejiaointel@users.noreply.github.com> Date: Tue, 15 Apr 2025 09:14:32 -0700 Subject: [PATCH 7/8] Fix python examples fail (#108) Use margin check and add tests to pipeline. Fixes #107. --- .github/workflows/cibuildwheel.yml | 6 ++++++ examples/python/example_vamana.py | 10 +++++----- examples/python/example_vamana_dynamic.py | 10 +++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml index 378d0c8cd..87198b983 100644 --- a/.github/workflows/cibuildwheel.yml +++ b/.github/workflows/cibuildwheel.yml @@ -60,3 +60,9 @@ jobs: working-directory: ${{ runner.temp }} run: python -m unittest discover -s ${GITHUB_WORKSPACE}/bindings/python + - name: Run examples + env: + PYTHONPATH: ${{ runner.temp }}/usr + CTEST_OUTPUT_ON_FAILURE: 1 + working-directory: ${{ runner.temp }} + run: python -m unittest discover -p "example*.py" -s ${GITHUB_WORKSPACE}/examples/python diff --git a/examples/python/example_vamana.py b/examples/python/example_vamana.py index b988a07c9..b8346bf9d 100644 --- a/examples/python/example_vamana.py +++ b/examples/python/example_vamana.py @@ -21,11 +21,12 @@ # [imports] DEBUG_MODE = False -def assert_equal(lhs, rhs, message: str = ""): +def assert_equal(lhs, rhs, message: str = "", epsilon = 0.05): if DEBUG_MODE: print(f"{message}: {lhs} == {rhs}") else: - assert lhs == rhs, message + assert lhs < rhs + epsilon, message + assert lhs > rhs - epsilon, message def run_test_float(index, queries, groundtruth): expected = { @@ -79,7 +80,6 @@ def run_test_build_two_level4_8(index, queries, groundtruth): test_data_dir = None def run(): - # ### # Generating test data # ### @@ -159,7 +159,7 @@ def run(): # Compare with the groundtruth. recall = svs.k_recall_at(groundtruth, I, 10, 10) print(f"Recall = {recall}") - assert(recall == 0.8288) + assert_equal(recall, 0.8288) # [perform-queries] # [search-window-size] @@ -213,7 +213,7 @@ def run(): # Compare with the groundtruth. recall = svs.k_recall_at(groundtruth, I, 10, 10) print(f"Recall = {recall}") - assert(recall == 0.8288) + assert_equal(recall, 0.8288) # [loading] ##### Begin Test diff --git a/examples/python/example_vamana_dynamic.py b/examples/python/example_vamana_dynamic.py index 3d57bd12d..45f087b27 100644 --- a/examples/python/example_vamana_dynamic.py +++ b/examples/python/example_vamana_dynamic.py @@ -22,11 +22,12 @@ # [imports] DEBUG_MODE = False -def assert_equal(lhs, rhs, message: str = ""): +def assert_equal(lhs, rhs, message: str = "", epsilon = 0.05): if DEBUG_MODE: print(f"{message}: {lhs} == {rhs}") else: - assert lhs == rhs, message + assert lhs < rhs + epsilon, message + assert lhs > rhs - epsilon, message def run_test_float(index, queries, groundtruth): expected = { @@ -118,7 +119,7 @@ def run(): # Compare with the groundtruth. recall = svs.k_recall_at(groundtruth, I, 10, 10) print(f"Recall = {recall}") - assert(recall == 0.8202) + assert_equal(recall, 0.8202) # [perform-queries] ##### Begin Test @@ -158,8 +159,7 @@ def run(): # Compare with the groundtruth. recall = svs.k_recall_at(groundtruth, I, 10, 10) print(f"Recall = {recall}") - assert(recall == 0.8202) - + assert_equal(recall, 0.8202) ##### Begin Test run_test_float(index, queries, groundtruth) From d1678cfbe734326392c0290d7973027e7e38b038 Mon Sep 17 00:00:00 2001 From: Dmitry Razdoburdin <> Date: Tue, 15 Apr 2025 23:30:34 -0700 Subject: [PATCH 8/8] simplify x86 vs arm dispatching --- include/svs/core/distance/cosine.h | 7 +------ include/svs/core/distance/euclidean.h | 8 +------- include/svs/core/distance/inner_product.h | 8 +------- include/svs/core/distance/simd_utils.h | 4 ++++ include/svs/lib/spinlock.h | 1 - 5 files changed, 7 insertions(+), 21 deletions(-) diff --git a/include/svs/core/distance/cosine.h b/include/svs/core/distance/cosine.h index f00430756..9738e881e 100644 --- a/include/svs/core/distance/cosine.h +++ b/include/svs/core/distance/cosine.h @@ -18,6 +18,7 @@ // svs #include "svs/core/distance/distance_core.h" +#include "svs/core/distance/simd_utils.h" #include "svs/lib/saveload.h" #include "svs/lib/static.h" @@ -29,12 +30,6 @@ #include #include -SVS_VALIDATE_BOOL_ENV(SVS_AVX512_F) -#if SVS_AVX512_F -#include "svs/core/distance/simd_utils.h" -#include -#endif // SVS_AVX512_F - namespace svs::distance { // Forward declare implementation to allow entry point to be near the top. template struct CosineSimilarityImpl; diff --git a/include/svs/core/distance/euclidean.h b/include/svs/core/distance/euclidean.h index 3b4d5d6de..2fc86986d 100644 --- a/include/svs/core/distance/euclidean.h +++ b/include/svs/core/distance/euclidean.h @@ -18,6 +18,7 @@ // svs #include "svs/core/distance/distance_core.h" +#include "svs/core/distance/simd_utils.h" #include "svs/lib/float16.h" #include "svs/lib/preprocessor.h" #include "svs/lib/saveload.h" @@ -31,13 +32,6 @@ #include #include -SVS_VALIDATE_BOOL_ENV(SVS_AVX512_F) -SVS_VALIDATE_BOOL_ENV(SVS_AVX2) -#if SVS_AVX512_F || SVS_AVX2 -#include "svs/core/distance/simd_utils.h" -#include -#endif // SVS_AVX512_F || SVS_AVX2 - // Implementation Notes regarding Intel(R) AVX Extentions // Top most entry in the bulleted list underneath each type pair is the preferred // implementation based on the available extension. diff --git a/include/svs/core/distance/inner_product.h b/include/svs/core/distance/inner_product.h index 6496dabfa..2ad51e178 100644 --- a/include/svs/core/distance/inner_product.h +++ b/include/svs/core/distance/inner_product.h @@ -18,6 +18,7 @@ // svs #include "svs/core/distance/distance_core.h" +#include "svs/core/distance/simd_utils.h" #include "svs/lib/float16.h" #include "svs/lib/preprocessor.h" #include "svs/lib/saveload.h" @@ -29,13 +30,6 @@ #include #include -SVS_VALIDATE_BOOL_ENV(SVS_AVX512_F) -SVS_VALIDATE_BOOL_ENV(SVS_AVX2) -#if SVS_AVX512_F || SVS_AVX2 -#include "svs/core/distance/simd_utils.h" -#include -#endif // SVS_AVX512_F || SVS_AVX2 - namespace svs::distance { // Forward declare implementation to allow entry point to be near the top. template struct IPImpl; diff --git a/include/svs/core/distance/simd_utils.h b/include/svs/core/distance/simd_utils.h index c5fc43d6d..db7c3ff7b 100644 --- a/include/svs/core/distance/simd_utils.h +++ b/include/svs/core/distance/simd_utils.h @@ -16,6 +16,8 @@ #pragma once +#if defined(__i386__) || defined(__x86_64__) + #include #include #include @@ -369,3 +371,5 @@ template <> struct ConvertForVNNI { } // namespace simd } // namespace svs + +#endif // __i386__ || __x86_64__ diff --git a/include/svs/lib/spinlock.h b/include/svs/lib/spinlock.h index 952c5101e..52f644b38 100644 --- a/include/svs/lib/spinlock.h +++ b/include/svs/lib/spinlock.h @@ -17,7 +17,6 @@ #pragma once #include -// #include // __cpp_inline_assembly namespace svs {