Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
b1313a4
refactor: add quantizer and distance
richyreachy Jun 29, 2026
45d9b54
fix: add turo quantizer
richyreachy Jun 30, 2026
e82d73f
refactor: add quantizer
richyreachy Jun 30, 2026
829f53e
refactor: update meta
richyreachy Jun 30, 2026
f084630
refactor: update meta
richyreachy Jun 30, 2026
c3c4ca3
refactor: add fp32 quantizer
richyreachy Jun 30, 2026
ec4ea1f
refactor: add quantizer
richyreachy Jun 30, 2026
e36f0c5
refactor: quantizer
richyreachy Jun 30, 2026
c1cdd0b
refactor: add scalar
richyreachy Jun 30, 2026
628982d
fix: fix cosine
richyreachy Jul 1, 2026
de33220
fix: add quantizer
richyreachy Jul 1, 2026
49780f8
fix: fix quantizer
richyreachy Jul 1, 2026
b1d4849
fix: remove unused var
richyreachy Jul 2, 2026
f0fdf5d
fix: header
richyreachy Jul 2, 2026
0c4cec6
fix: header
richyreachy Jul 2, 2026
73f5bc3
fix: header
richyreachy Jul 2, 2026
89843dd
add preprocessor
zzlin237 Jul 2, 2026
437a754
fix: fix symbol
richyreachy Jul 2, 2026
e16cda5
add untest
zzlin237 Jul 2, 2026
22b87d8
Merge remote-tracking branch 'origin/refactor/turbo_quantizer' into r…
zzlin237 Jul 2, 2026
f3a6782
remove extra doc
zzlin237 Jul 2, 2026
642b8bf
Merge remote-tracking branch 'upstream/main' into refactor/turbo_prep…
zzlin237 Jul 3, 2026
79a08eb
style: fix clang-format issues from upstream merge
zzlin237 Jul 3, 2026
78ace2b
style: fix clang-format issues in turbo module
zzlin237 Jul 3, 2026
b80bc4d
fix: LNK1120
zzlin237 Jul 3, 2026
281fdb4
Rename to conform to the style guide
zzlin237 Jul 3, 2026
10cbe03
Rename to conform to the style guide
zzlin237 Jul 3, 2026
c2026cb
Merge branch 'main' into refactor/turbo_quantizer
richyreachy Jul 3, 2026
c468e12
Merge branch 'main' into refactor/turbo_preprocessor
zzlin237 Jul 3, 2026
cb66180
Merge branch 'main' into refactor/turbo_quantizer
richyreachy Jul 6, 2026
3470e4b
Merge remote-tracking branch 'upstream/main' into refactor/turbo_prep…
zzlin237 Jul 7, 2026
a6ecfb6
Merge remote-tracking branch 'richyreachy/refactor/turbo_quantizer' i…
zzlin237 Jul 7, 2026
cb36a54
Merge branch 'refactor/turbo_preprocessor' of https://github.com/zzli…
zzlin237 Jul 7, 2026
1c2de23
Merge remote-tracking branch 'upstream/main' into refactor/turbo_prep…
zzlin237 Jul 7, 2026
8406e9f
remove train to create int fht
zzlin237 Jul 7, 2026
ac17ee9
fix: add neon
richyreachy Jul 10, 2026
7bb01c3
fix: add arm arch
richyreachy Jul 10, 2026
bd1bd50
Merge branch 'refactor/turbo_quantizer' of github.com:richyreachy/zve…
richyreachy Jul 10, 2026
6abf1b8
CpuArchType FHT
zzlin237 Jul 10, 2026
ea816cc
reset preprocessor
zzlin237 Jul 10, 2026
03700da
Merge remote-tracking branch 'richyreachy/refactor/turbo_quantizer' i…
zzlin237 Jul 10, 2026
b909b4d
add neon
zzlin237 Jul 10, 2026
c826ab8
Merge branch 'main' into refactor/turbo_quantizer
richyreachy Jul 10, 2026
403c123
fix: add meta
richyreachy Jul 10, 2026
b3e6a56
fix: query meta
richyreachy Jul 10, 2026
11e8966
Merge remote-tracking branch 'richyreachy/refactor/turbo_quantizer' i…
zzlin237 Jul 13, 2026
3cd090c
clang-format
zzlin237 Jul 13, 2026
4287131
fix: fix alignment
richyreachy Jul 15, 2026
3943566
refactor: move header file
richyreachy Jul 15, 2026
05d43de
Merge branch 'main' into refactor/turbo_quantizer
richyreachy Jul 15, 2026
084b475
fix: remove comment
richyreachy Jul 15, 2026
e6fa14e
Merge branch 'refactor/turbo_quantizer' of github.com:richyreachy/zve…
richyreachy Jul 15, 2026
931c61d
tmp
zzlin237 Jul 15, 2026
7552df5
fix: fix empty line
richyreachy Jul 15, 2026
28fe49a
add RotateType
zzlin237 Jul 15, 2026
bc9149d
add RotateType
zzlin237 Jul 15, 2026
7606006
Merge remote-tracking branch 'richyreachy/refactor/turbo_quantizer' i…
zzlin237 Jul 15, 2026
19c6578
merge main
zzlin237 Jul 15, 2026
8997541
Unified Scheduling Mode
zzlin237 Jul 16, 2026
ec946b1
Adjust Directory
zzlin237 Jul 16, 2026
6b20747
fix enum
zzlin237 Jul 17, 2026
4065035
add helper
zzlin237 Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ allure-*
!build_android.sh
!build_ios.sh

# congfig
# config
doc/
config/
examples/python/
examples/c_api/
logs/
logs/
23 changes: 23 additions & 0 deletions src/include/zvec/turbo/turbo.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
// limitations under the License.
#pragma once

#include <cstddef>
#include <cstdint>
#include <functional>
#include <zvec/ailego/math_batch/utils.h>

Expand All @@ -33,6 +35,19 @@ using QueryPreprocessFunc =
using UniformQuantizeFunc = void (*)(const float *in, size_t dim, float scale,
float bias, int8_t *out);

// Generic rotate / unrotate function pointer types.
// ctx is an opaque context (e.g. FhtCtx*) managed by the caller.
using RotateFunc = void (*)(const float *in, float *out, size_t in_dim,
size_t out_dim, void *ctx);
using UnrotateFunc = void (*)(const float *in, float *out, size_t in_dim,
size_t out_dim, void *ctx);

// ISA-dispatched rotate/unrotate kernels.
struct RotatorKernels {
RotateFunc rotate = nullptr;
UnrotateFunc unrotate = nullptr;
};

enum class MetricType {
kSquaredEuclidean,
kCosine,
Expand All @@ -59,6 +74,10 @@ enum class QuantizeType {
kRabit
};

enum class RotateType : uint16_t {
kFht = 1, //!< O(d log d) FHT-based Kac random rotation
};

enum class CpuArchType {
kAuto,
kScalar,
Expand Down Expand Up @@ -95,4 +114,8 @@ QueryPreprocessFunc get_query_preprocess_func(
// interface can grow to cover other output types (e.g. fp16) in the future.
UniformQuantizeFunc get_uniform_quantize_func(DataType data_type);

// Returns rotator kernels dispatched for the current CPU.
RotatorKernels get_rotator_kernels(
RotateType rotate_type, CpuArchType cpu_arch_type = CpuArchType::kAuto);

} // namespace zvec::turbo
30 changes: 24 additions & 6 deletions src/turbo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,41 @@ if(NOT ANDROID AND AUTO_DETECT_ARCH)
if (HOST_ARCH MATCHES "^(x86|x64)$")
setup_compiler_march_for_x86(TURBO_MARCH_FLAG_SSE TURBO_MARCH_FLAG_AVX2 TURBO_MARCH_FLAG_AVX512 TURBO_MARCH_FLAG_AVX512FP16)
elseif (HOST_ARCH MATCHES "^(arm|arm64)$")
# ARM64 architecture - no special march flags needed for now
# NEON implementations can be added here if needed
message(STATUS "turbo: ARM64 detected, skipping x86-specific optimizations")
# ARM64 architecture - NEON is enabled by default on aarch64,
# no special march flags needed.
message(STATUS "turbo: ARM64 detected, NEON enabled by default")
endif()
endif()

file(GLOB_RECURSE ALL_SRCS *.cc *.c *.h)

# Set per-file compile flags for AVX512-VNNI sources.
# Set per-file compile flags for SIMD sources.
# set_source_files_properties is directory-scoped, so it must be called in the
# same directory that adds the sources to a target (i.e. here, not in a
# subdirectory).
if(NOT ANDROID AND AUTO_DETECT_ARCH)
if (HOST_ARCH MATCHES "^(x86|x64)$")
file(GLOB_RECURSE AVX512_VNNI_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/distance/avx512_vnni/*.cc)
# SSE
file(GLOB_RECURSE SSE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/distance/sse/*.cc)
set_source_files_properties(
${AVX512_VNNI_SRCS}
${SSE_SRCS}
PROPERTIES
COMPILE_FLAGS "${TURBO_MARCH_FLAG_SSE}"
)

# AVX2
file(GLOB_RECURSE AVX2_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/distance/avx2/*.cc)
set_source_files_properties(
${AVX2_SRCS}
PROPERTIES
COMPILE_FLAGS "${TURBO_MARCH_FLAG_AVX2}"
)

# AVX512 (avx512_vnni, avx512/fht, and turbo.cc dispatch all use AVX512 march)
file(GLOB_RECURSE AVX512_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/distance/avx512_vnni/*.cc ${CMAKE_CURRENT_SOURCE_DIR}/distance/avx512/*.cc)
list(APPEND AVX512_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/turbo.cc)
set_source_files_properties(
${AVX512_SRCS}
PROPERTIES
COMPILE_FLAGS "${TURBO_MARCH_FLAG_AVX512}"
)
Expand Down
154 changes: 154 additions & 0 deletions src/turbo/distance/avx2/rotate/fht/fht.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2025-present the zvec project
//
// 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.

#if defined(__AVX2__)
Comment thread
richyreachy marked this conversation as resolved.

#include "fht.h"
#include <immintrin.h>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include "common/fht_common.h"

namespace zvec::turbo::avx2 {

void fht_flip_sign_avx2(const uint8_t *flip, float *data, size_t dim) {
size_t simd_end = dim & ~31u;
constexpr size_t kChunk = 32;
const __m256i bit_select =
_mm256_setr_epi32(0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80);
const __m256 sign_flip = _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000));
for (size_t i = 0; i < simd_end; i += kChunk) {
uint32_t mask_bits;
std::memcpy(&mask_bits, &flip[i / 8], sizeof(mask_bits));
for (int b = 0; b < 4; ++b) {
__m256i mb = _mm256_set1_epi32((mask_bits >> (b * 8)) & 0xFF);
__m256i test = _mm256_and_si256(mb, bit_select);
__m256i cmp = _mm256_cmpeq_epi32(test, bit_select);
__m256 xor_mask = _mm256_and_ps(_mm256_castsi256_ps(cmp), sign_flip);
__m256 v = _mm256_loadu_ps(&data[i + b * 8]);
v = _mm256_xor_ps(v, xor_mask);
_mm256_storeu_ps(&data[i + b * 8], v);
}
}
// Scalar tail
for (size_t i = simd_end; i < dim; ++i) {
if (flip[i / 8] & (1u << (i % 8))) {
data[i] = -data[i];
}
}
}

void fht_kacs_walk_avx2(float *data, size_t len) {
size_t half = len / 2;
size_t base = len % 2;
size_t offset = base + half;
size_t half_end = half & ~7u;
for (size_t i = 0; i < half_end; i += 8) {
__m256 x = _mm256_loadu_ps(&data[i]);
__m256 y = _mm256_loadu_ps(&data[i + offset]);
_mm256_storeu_ps(&data[i], _mm256_add_ps(x, y));
_mm256_storeu_ps(&data[i + offset], _mm256_sub_ps(x, y));
}
// Scalar tail
for (size_t i = half_end; i < half; ++i) {
float x = data[i];
float y = data[i + offset];
data[i] = x + y;
data[i + offset] = x - y;
}
if (base != 0) {
data[half] *= std::sqrt(2.0f);
}
}

void fht_inv_kacs_walk_avx2(float *data, size_t len) {
size_t half = len / 2;
size_t base = len % 2;
size_t offset = base + half;
if (base != 0) {
data[half] *= std::sqrt(0.5f);
}
size_t half_end = half & ~7u;
const __m256 half_fac = _mm256_set1_ps(0.5f);
for (size_t i = 0; i < half_end; i += 8) {
__m256 a = _mm256_loadu_ps(&data[i]);
__m256 b = _mm256_loadu_ps(&data[i + offset]);
_mm256_storeu_ps(&data[i], _mm256_mul_ps(_mm256_add_ps(a, b), half_fac));
_mm256_storeu_ps(&data[i + offset],
_mm256_mul_ps(_mm256_sub_ps(a, b), half_fac));
}
// Scalar tail
for (size_t i = half_end; i < half; ++i) {
float a = data[i];
float b = data[i + offset];
data[i] = (a + b) * 0.5f;
data[i + offset] = (a - b) * 0.5f;
}
}

void fht_inplace_avx2(float *data, size_t n) {
for (size_t len = 1; len < n; len <<= 1) {
size_t step = len << 1;
size_t simd_end = len & ~7u;
for (size_t i = 0; i < n; i += step) {
for (size_t j = 0; j < simd_end; j += 8) {
__m256 u = _mm256_loadu_ps(&data[i + j]);
__m256 v = _mm256_loadu_ps(&data[i + j + len]);
_mm256_storeu_ps(&data[i + j], _mm256_add_ps(u, v));
_mm256_storeu_ps(&data[i + j + len], _mm256_sub_ps(u, v));
}
for (size_t j = simd_end; j < len; ++j) {
float u = data[i + j];
float v = data[i + j + len];
data[i + j] = u + v;
data[i + j + len] = u - v;
}
}
}
}

void fht_vec_rescale_avx2(float *data, size_t n, float factor) {
const __m256 fac = _mm256_set1_ps(factor);
size_t simd_end = n & ~7u;
for (size_t i = 0; i < simd_end; i += 8) {
__m256 v = _mm256_loadu_ps(&data[i]);
_mm256_storeu_ps(&data[i], _mm256_mul_ps(v, fac));
}
// Scalar tail
for (size_t i = simd_end; i < n; ++i) {
data[i] *= factor;
}
}

void fht_rotate_avx2(const float * /*in*/, float *out, size_t in_dim,
size_t /*out_dim*/, void *ctx) {
static constexpr FhtPrimitives kPrim = {
fht_flip_sign_avx2, fht_inplace_avx2, fht_kacs_walk_avx2,
fht_inv_kacs_walk_avx2, fht_vec_rescale_avx2};
fht_rotate_impl(out, in_dim, ctx, kPrim);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in参数完全没用到,要求输入已经在out了,这个接口有问题吧?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

因为操作全是原地操作,地址分配已经放到在上层完成,此处我就直接输入out了

}

void fht_unrotate_avx2(const float * /*in*/, float *out, size_t in_dim,
size_t /*out_dim*/, void *ctx) {
static constexpr FhtPrimitives kPrim = {
fht_flip_sign_avx2, fht_inplace_avx2, fht_kacs_walk_avx2,
fht_inv_kacs_walk_avx2, fht_vec_rescale_avx2};
fht_unrotate_impl(out, in_dim, ctx, kPrim);
}

} // namespace zvec::turbo::avx2

#endif // __AVX2__
49 changes: 49 additions & 0 deletions src/turbo/distance/avx2/rotate/fht/fht.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2025-present the zvec project
//
// 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.

#pragma once

#if defined(__AVX2__)

#include <cstddef>
#include <cstdint>

namespace zvec::turbo::avx2 {

//! Apply bitwise sign-flip mask to a float vector (AVX2).
void fht_flip_sign_avx2(const uint8_t *flip, float *data, size_t dim);

//! Apply KacsWalk butterfly operation (AVX2).
void fht_kacs_walk_avx2(float *data, size_t len);

//! Inverse KacsWalk butterfly operation (AVX2).
void fht_inv_kacs_walk_avx2(float *data, size_t len);

//! In-place Fast Hadamard Transform (AVX2, n must be power-of-2).
void fht_inplace_avx2(float *data, size_t n);

//! Element-wise rescale: data[i] *= factor (AVX2).
void fht_vec_rescale_avx2(float *data, size_t n, float factor);

//! Forward FHT rotation (AVX2).
void fht_rotate_avx2(const float *in, float *out, size_t in_dim, size_t out_dim,
void *ctx);

//! Inverse FHT rotation (AVX2).
void fht_unrotate_avx2(const float *in, float *out, size_t in_dim,
size_t out_dim, void *ctx);

} // namespace zvec::turbo::avx2

#endif // __AVX2__
Loading