faiss 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/Clustering.h +8 -0
- data/vendor/faiss/faiss/Index.h +1 -1
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +23 -2
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +12 -140
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +6 -14
- data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
- data/vendor/faiss/faiss/IndexFlat.cpp +8 -4
- data/vendor/faiss/faiss/IndexFlat.h +2 -2
- data/vendor/faiss/faiss/IndexHNSW.cpp +301 -91
- data/vendor/faiss/faiss/IndexHNSW.h +31 -7
- data/vendor/faiss/faiss/IndexIDMap.cpp +11 -6
- data/vendor/faiss/faiss/IndexIVF.cpp +19 -4
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +9 -1
- data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
- data/vendor/faiss/faiss/IndexShards.cpp +3 -3
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +4 -3
- data/vendor/faiss/faiss/SuperKMeans.cpp +31 -8
- data/vendor/faiss/faiss/SuperKMeans.h +3 -2
- data/vendor/faiss/faiss/VectorTransform.cpp +38 -0
- data/vendor/faiss/faiss/VectorTransform.h +3 -0
- data/vendor/faiss/faiss/clone_index.cpp +3 -0
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
- data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
- data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -5
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +65 -42
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +5 -2
- data/vendor/faiss/faiss/impl/HNSW.cpp +419 -115
- data/vendor/faiss/faiss/impl/HNSW.h +46 -7
- data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
- data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
- data/vendor/faiss/faiss/impl/Panorama.h +11 -2
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +4 -4
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +1 -1
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +74 -8
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +47 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +2 -2
- data/vendor/faiss/faiss/impl/ResultHandler.h +9 -3
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +32 -30
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +6 -10
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +89 -13
- data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
- data/vendor/faiss/faiss/impl/index_read.cpp +130 -29
- data/vendor/faiss/faiss/impl/index_write.cpp +31 -26
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +6 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +6 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +37 -17
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +109 -10
- data/vendor/faiss/faiss/impl/simd_dispatch.h +40 -22
- data/vendor/faiss/faiss/index_factory.cpp +8 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +7 -4
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +10 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +16 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +8 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +9 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
- data/vendor/faiss/faiss/utils/distances.cpp +20 -13
- data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
- data/vendor/faiss/faiss/utils/hamming.cpp +15 -9
- data/vendor/faiss/faiss/utils/hamming.h +10 -1
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +93 -55
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +57 -40
- data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +21 -24
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +172 -67
- data/vendor/faiss/faiss/utils/simd_levels.h +26 -15
- metadata +6 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
|
@@ -16,6 +16,42 @@
|
|
|
16
16
|
|
|
17
17
|
namespace faiss {
|
|
18
18
|
|
|
19
|
+
template <typename Vec, typename Reduce>
|
|
20
|
+
static inline float rvv_reduce(
|
|
21
|
+
Vec value,
|
|
22
|
+
size_t vl,
|
|
23
|
+
float identity,
|
|
24
|
+
Reduce reduce) {
|
|
25
|
+
vfloat32m1_t init = __riscv_vfmv_s_f_f32m1(identity, 1);
|
|
26
|
+
vfloat32m1_t result = reduce(value, init, vl);
|
|
27
|
+
return __riscv_vfmv_f_s_f32m1_f32(result);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static inline size_t rvv_argmin(const float* values, size_t n) {
|
|
31
|
+
size_t vlmax = __riscv_vsetvlmax_e32m8();
|
|
32
|
+
vfloat32m8_t vmin = __riscv_vfmv_v_f_f32m8(__builtin_inff(), vlmax);
|
|
33
|
+
size_t i = 0;
|
|
34
|
+
while (i < n) {
|
|
35
|
+
size_t vl = __riscv_vsetvl_e32m8(n - i);
|
|
36
|
+
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
|
|
37
|
+
vmin = __riscv_vfmin_vv_f32m8_tu(vmin, vmin, vd, vl);
|
|
38
|
+
i += vl;
|
|
39
|
+
}
|
|
40
|
+
float min_val = rvv_reduce(
|
|
41
|
+
vmin, vlmax, __builtin_inff(), __riscv_vfredmin_vs_f32m8_f32m1);
|
|
42
|
+
i = 0;
|
|
43
|
+
while (i < n) {
|
|
44
|
+
size_t vl = __riscv_vsetvl_e32m8(n - i);
|
|
45
|
+
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
|
|
46
|
+
long j = __riscv_vfirst_m_b4(
|
|
47
|
+
__riscv_vmfeq_vf_f32m8_b4(vd, min_val, vl), vl);
|
|
48
|
+
if (j >= 0)
|
|
49
|
+
return i + static_cast<size_t>(j);
|
|
50
|
+
i += vl;
|
|
51
|
+
}
|
|
52
|
+
return n;
|
|
53
|
+
}
|
|
54
|
+
|
|
19
55
|
template <>
|
|
20
56
|
float fvec_norm_L2sqr<SIMDLevel::RISCV_RVV>(const float* x, size_t d) {
|
|
21
57
|
size_t vlmax = __riscv_vsetvlmax_e32m8();
|
|
@@ -27,9 +63,7 @@ float fvec_norm_L2sqr<SIMDLevel::RISCV_RVV>(const float* x, size_t d) {
|
|
|
27
63
|
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
|
|
28
64
|
i += vl;
|
|
29
65
|
}
|
|
30
|
-
|
|
31
|
-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
|
|
32
|
-
return __riscv_vfmv_f_s_f32m1_f32(sum);
|
|
66
|
+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
|
|
33
67
|
}
|
|
34
68
|
|
|
35
69
|
template <>
|
|
@@ -48,9 +82,7 @@ float fvec_L2sqr<SIMDLevel::RISCV_RVV>(
|
|
|
48
82
|
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
|
|
49
83
|
i += vl;
|
|
50
84
|
}
|
|
51
|
-
|
|
52
|
-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
|
|
53
|
-
return __riscv_vfmv_f_s_f32m1_f32(sum);
|
|
85
|
+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
|
|
54
86
|
}
|
|
55
87
|
|
|
56
88
|
template <>
|
|
@@ -68,9 +100,7 @@ float fvec_inner_product<SIMDLevel::RISCV_RVV>(
|
|
|
68
100
|
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vy, vl);
|
|
69
101
|
i += vl;
|
|
70
102
|
}
|
|
71
|
-
|
|
72
|
-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
|
|
73
|
-
return __riscv_vfmv_f_s_f32m1_f32(sum);
|
|
103
|
+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
|
|
74
104
|
}
|
|
75
105
|
|
|
76
106
|
template <>
|
|
@@ -87,9 +117,7 @@ float fvec_L1<SIMDLevel::RISCV_RVV>(const float* x, const float* y, size_t d) {
|
|
|
87
117
|
acc = __riscv_vfadd_vv_f32m8_tu(acc, acc, vx, vl);
|
|
88
118
|
i += vl;
|
|
89
119
|
}
|
|
90
|
-
|
|
91
|
-
sum = __riscv_vfredusum_vs_f32m8_f32m1(acc, sum, vlmax);
|
|
92
|
-
return __riscv_vfmv_f_s_f32m1_f32(sum);
|
|
120
|
+
return rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
|
|
93
121
|
}
|
|
94
122
|
|
|
95
123
|
template <>
|
|
@@ -109,9 +137,7 @@ float fvec_Linf<SIMDLevel::RISCV_RVV>(
|
|
|
109
137
|
vmax = __riscv_vfmax_vv_f32m8_tu(vmax, vmax, vx, vl);
|
|
110
138
|
i += vl;
|
|
111
139
|
}
|
|
112
|
-
|
|
113
|
-
max = __riscv_vfredmax_vs_f32m8_f32m1(vmax, max, vlmax);
|
|
114
|
-
return __riscv_vfmv_f_s_f32m1_f32(max);
|
|
140
|
+
return rvv_reduce(vmax, vlmax, 0.0f, __riscv_vfredmax_vs_f32m8_f32m1);
|
|
115
141
|
}
|
|
116
142
|
|
|
117
143
|
template <>
|
|
@@ -126,10 +152,29 @@ void fvec_inner_product_batch_4<SIMDLevel::RISCV_RVV>(
|
|
|
126
152
|
float& dis1,
|
|
127
153
|
float& dis2,
|
|
128
154
|
float& dis3) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
155
|
+
size_t vlmax = __riscv_vsetvlmax_e32m4();
|
|
156
|
+
vfloat32m4_t vacc0 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
157
|
+
vfloat32m4_t vacc1 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
158
|
+
vfloat32m4_t vacc2 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
159
|
+
vfloat32m4_t vacc3 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
160
|
+
size_t i = 0;
|
|
161
|
+
while (i < d) {
|
|
162
|
+
size_t vl = __riscv_vsetvl_e32m4(d - i);
|
|
163
|
+
vfloat32m4_t vx = __riscv_vle32_v_f32m4(x + i, vl);
|
|
164
|
+
vfloat32m4_t vy = __riscv_vle32_v_f32m4(y0 + i, vl);
|
|
165
|
+
vacc0 = __riscv_vfmacc_vv_f32m4_tu(vacc0, vx, vy, vl);
|
|
166
|
+
vy = __riscv_vle32_v_f32m4(y1 + i, vl);
|
|
167
|
+
vacc1 = __riscv_vfmacc_vv_f32m4_tu(vacc1, vx, vy, vl);
|
|
168
|
+
vy = __riscv_vle32_v_f32m4(y2 + i, vl);
|
|
169
|
+
vacc2 = __riscv_vfmacc_vv_f32m4_tu(vacc2, vx, vy, vl);
|
|
170
|
+
vy = __riscv_vle32_v_f32m4(y3 + i, vl);
|
|
171
|
+
vacc3 = __riscv_vfmacc_vv_f32m4_tu(vacc3, vx, vy, vl);
|
|
172
|
+
i += vl;
|
|
173
|
+
}
|
|
174
|
+
dis0 = rvv_reduce(vacc0, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
175
|
+
dis1 = rvv_reduce(vacc1, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
176
|
+
dis2 = rvv_reduce(vacc2, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
177
|
+
dis3 = rvv_reduce(vacc3, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
133
178
|
}
|
|
134
179
|
|
|
135
180
|
template <>
|
|
@@ -144,10 +189,33 @@ void fvec_L2sqr_batch_4<SIMDLevel::RISCV_RVV>(
|
|
|
144
189
|
float& dis1,
|
|
145
190
|
float& dis2,
|
|
146
191
|
float& dis3) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
192
|
+
size_t vlmax = __riscv_vsetvlmax_e32m4();
|
|
193
|
+
vfloat32m4_t vacc0 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
194
|
+
vfloat32m4_t vacc1 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
195
|
+
vfloat32m4_t vacc2 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
196
|
+
vfloat32m4_t vacc3 = __riscv_vfmv_v_f_f32m4(0.0f, vlmax);
|
|
197
|
+
size_t i = 0;
|
|
198
|
+
while (i < d) {
|
|
199
|
+
size_t vl = __riscv_vsetvl_e32m4(d - i);
|
|
200
|
+
vfloat32m4_t vx = __riscv_vle32_v_f32m4(x + i, vl);
|
|
201
|
+
vfloat32m4_t vy = __riscv_vle32_v_f32m4(y0 + i, vl);
|
|
202
|
+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
|
|
203
|
+
vacc0 = __riscv_vfmacc_vv_f32m4_tu(vacc0, vy, vy, vl);
|
|
204
|
+
vy = __riscv_vle32_v_f32m4(y1 + i, vl);
|
|
205
|
+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
|
|
206
|
+
vacc1 = __riscv_vfmacc_vv_f32m4_tu(vacc1, vy, vy, vl);
|
|
207
|
+
vy = __riscv_vle32_v_f32m4(y2 + i, vl);
|
|
208
|
+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
|
|
209
|
+
vacc2 = __riscv_vfmacc_vv_f32m4_tu(vacc2, vy, vy, vl);
|
|
210
|
+
vy = __riscv_vle32_v_f32m4(y3 + i, vl);
|
|
211
|
+
vy = __riscv_vfsub_vv_f32m4(vx, vy, vl);
|
|
212
|
+
vacc3 = __riscv_vfmacc_vv_f32m4_tu(vacc3, vy, vy, vl);
|
|
213
|
+
i += vl;
|
|
214
|
+
}
|
|
215
|
+
dis0 = rvv_reduce(vacc0, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
216
|
+
dis1 = rvv_reduce(vacc1, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
217
|
+
dis2 = rvv_reduce(vacc2, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
218
|
+
dis3 = rvv_reduce(vacc3, vlmax, 0.0f, __riscv_vfredusum_vs_f32m4_f32m1);
|
|
151
219
|
}
|
|
152
220
|
|
|
153
221
|
template <>
|
|
@@ -168,9 +236,8 @@ void fvec_L2sqr_ny_transposed<SIMDLevel::RISCV_RVV>(
|
|
|
168
236
|
acc = __riscv_vfmacc_vv_f32m8_tu(acc, vx, vx, vl);
|
|
169
237
|
i += vl;
|
|
170
238
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
float x_sqlen = __riscv_vfmv_f_s_f32m1_f32(sum);
|
|
239
|
+
float x_sqlen =
|
|
240
|
+
rvv_reduce(acc, vlmax, 0.0f, __riscv_vfredusum_vs_f32m8_f32m1);
|
|
174
241
|
i = 0;
|
|
175
242
|
while (i < ny) {
|
|
176
243
|
size_t vl = __riscv_vsetvl_e32m8(ny - i);
|
|
@@ -214,35 +281,6 @@ void fvec_L2sqr_ny<SIMDLevel::RISCV_RVV>(
|
|
|
214
281
|
}
|
|
215
282
|
}
|
|
216
283
|
|
|
217
|
-
// Index of the first element equal to the minimum of values[0..n), or n when
|
|
218
|
-
// there is none (e.g. n == 0). Shared by the *_nearest and madd_and_argmin
|
|
219
|
-
// kernels so the vfmin/vfredmin/vfirst sequence lives in one place.
|
|
220
|
-
static size_t rvv_argmin(const float* values, size_t n) {
|
|
221
|
-
size_t vlmax = __riscv_vsetvlmax_e32m8();
|
|
222
|
-
vfloat32m8_t vmin = __riscv_vfmv_v_f_f32m8(__builtin_inff(), vlmax);
|
|
223
|
-
size_t i = 0;
|
|
224
|
-
while (i < n) {
|
|
225
|
-
size_t vl = __riscv_vsetvl_e32m8(n - i);
|
|
226
|
-
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
|
|
227
|
-
vmin = __riscv_vfmin_vv_f32m8_tu(vmin, vmin, vd, vl);
|
|
228
|
-
i += vl;
|
|
229
|
-
}
|
|
230
|
-
vfloat32m1_t rmin = __riscv_vfmv_s_f_f32m1(__builtin_inff(), 1);
|
|
231
|
-
rmin = __riscv_vfredmin_vs_f32m8_f32m1(vmin, rmin, vlmax);
|
|
232
|
-
float min_val = __riscv_vfmv_f_s_f32m1_f32(rmin);
|
|
233
|
-
i = 0;
|
|
234
|
-
while (i < n) {
|
|
235
|
-
size_t vl = __riscv_vsetvl_e32m8(n - i);
|
|
236
|
-
vfloat32m8_t vd = __riscv_vle32_v_f32m8(values + i, vl);
|
|
237
|
-
long j = __riscv_vfirst_m_b4(
|
|
238
|
-
__riscv_vmfeq_vf_f32m8_b4(vd, min_val, vl), vl);
|
|
239
|
-
if (j >= 0)
|
|
240
|
-
return i + static_cast<size_t>(j);
|
|
241
|
-
i += vl;
|
|
242
|
-
}
|
|
243
|
-
return n;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
284
|
template <>
|
|
247
285
|
size_t fvec_L2sqr_ny_nearest<SIMDLevel::RISCV_RVV>(
|
|
248
286
|
float* distances_tmp_buffer,
|
|
@@ -623,16 +623,6 @@ namespace faiss::rabitq::multibit {
|
|
|
623
623
|
|
|
624
624
|
namespace {
|
|
625
625
|
|
|
626
|
-
inline float hsum_avx2(__m256 v) {
|
|
627
|
-
__m128 hi = _mm256_extractf128_ps(v, 1);
|
|
628
|
-
__m128 lo = _mm256_castps256_ps128(v);
|
|
629
|
-
lo = _mm_add_ps(lo, hi);
|
|
630
|
-
__m128 shuf = _mm_movehdup_ps(lo);
|
|
631
|
-
lo = _mm_add_ps(lo, shuf);
|
|
632
|
-
shuf = _mm_movehl_ps(shuf, lo);
|
|
633
|
-
return _mm_cvtss_f32(_mm_add_ss(lo, shuf));
|
|
634
|
-
}
|
|
635
|
-
|
|
636
626
|
inline float ip_1exbit_avx512(
|
|
637
627
|
const uint8_t* __restrict sign_bits,
|
|
638
628
|
const uint8_t* __restrict ex_code,
|
|
@@ -664,60 +654,86 @@ inline float ip_1exbit_avx512(
|
|
|
664
654
|
return result;
|
|
665
655
|
}
|
|
666
656
|
|
|
667
|
-
//
|
|
668
|
-
//
|
|
669
|
-
// VIA Eden X4 has AVX2 without BMI2.
|
|
657
|
+
// Needs BMI2 for _pext_u64. Some AVX2 CPUs lack it, and FAISS_BMI2_FLAGS can
|
|
658
|
+
// be empty, so the dispatcher falls back to the scalar path without it.
|
|
670
659
|
#ifdef __BMI2__
|
|
671
|
-
|
|
660
|
+
// Bitplane kernel for ex_bits >= 2, 16 dims per iteration. A bitplane is
|
|
661
|
+
// already a bitmask, so it goes into a mask register and one masked add
|
|
662
|
+
// applies its weight. Reads of ex_code run a few bytes past the ex-code
|
|
663
|
+
// section into the record's own trailing factors, so they stay in bounds.
|
|
664
|
+
inline float ip_bitplane_avx512(
|
|
672
665
|
const uint8_t* __restrict sign_bits,
|
|
673
666
|
const uint8_t* __restrict ex_code,
|
|
674
667
|
const float* __restrict rotated_q,
|
|
675
668
|
size_t d,
|
|
676
669
|
size_t ex_bits,
|
|
677
670
|
float cb) {
|
|
678
|
-
|
|
679
|
-
const
|
|
680
|
-
const __m256i bit_pos = _mm256_setr_epi32(1, 2, 4, 8, 16, 32, 64, 128);
|
|
681
|
-
const __m256i zero = _mm256_setzero_si256();
|
|
682
|
-
const __m256 v_cb = _mm256_set1_ps(cb);
|
|
671
|
+
__m512 acc = _mm512_setzero_ps();
|
|
672
|
+
const __m512 v_cb = _mm512_set1_ps(cb);
|
|
683
673
|
|
|
684
674
|
uint64_t pext_masks[7];
|
|
685
|
-
|
|
675
|
+
__m512 v_weights[8];
|
|
686
676
|
for (size_t b = 0; b < ex_bits; b++) {
|
|
687
677
|
uint64_t m = 0;
|
|
688
678
|
for (int j = 0; j < 8; j++) {
|
|
689
679
|
m |= (1ULL << (b + j * ex_bits));
|
|
690
680
|
}
|
|
691
681
|
pext_masks[b] = m;
|
|
692
|
-
v_weights[b] =
|
|
682
|
+
v_weights[b] = _mm512_set1_ps(static_cast<float>(1u << b));
|
|
693
683
|
}
|
|
694
|
-
v_weights[ex_bits] =
|
|
684
|
+
v_weights[ex_bits] = _mm512_set1_ps(static_cast<float>(1u << ex_bits));
|
|
695
685
|
|
|
696
686
|
size_t i = 0;
|
|
697
|
-
for (; i +
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
687
|
+
for (; i + 16 <= d; i += 16) {
|
|
688
|
+
uint16_t sb = 0;
|
|
689
|
+
memcpy(&sb, sign_bits + (i / 8), sizeof(uint16_t));
|
|
690
|
+
__m512 recon = _mm512_maskz_mov_ps(
|
|
691
|
+
static_cast<__mmask16>(sb), v_weights[ex_bits]);
|
|
692
|
+
|
|
693
|
+
uint64_t lo64 = 0;
|
|
694
|
+
uint64_t hi64 = 0;
|
|
695
|
+
memcpy(&lo64, ex_code + (i / 8) * ex_bits, sizeof(uint64_t));
|
|
696
|
+
memcpy(&hi64, ex_code + ((i / 8) + 1) * ex_bits, sizeof(uint64_t));
|
|
697
|
+
|
|
698
|
+
for (size_t b = 0; b < ex_bits; b++) {
|
|
699
|
+
const uint32_t plane =
|
|
700
|
+
static_cast<uint32_t>(_pext_u64(lo64, pext_masks[b])) |
|
|
701
|
+
(static_cast<uint32_t>(_pext_u64(hi64, pext_masks[b]))
|
|
702
|
+
<< 8);
|
|
703
|
+
recon = _mm512_mask_add_ps(
|
|
704
|
+
recon, static_cast<__mmask16>(plane), recon, v_weights[b]);
|
|
705
|
+
}
|
|
704
706
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
+
__m512 rq = _mm512_loadu_ps(rotated_q + i);
|
|
708
|
+
acc = _mm512_fmadd_ps(rq, _mm512_add_ps(recon, v_cb), acc);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Half-width step: keeps the scalar tail under 8 dims when d is a multiple
|
|
712
|
+
// of 8 but not of 16 (e.g. 200, 1000). The upper 8 lanes are masked off
|
|
713
|
+
// throughout, and rotated_q is loaded masked so nothing is read past the
|
|
714
|
+
// end.
|
|
715
|
+
if (i + 8 <= d) {
|
|
716
|
+
const __mmask16 low8 = static_cast<__mmask16>(0x00ff);
|
|
717
|
+
__m512 recon = _mm512_maskz_mov_ps(
|
|
718
|
+
static_cast<__mmask16>(sign_bits[i / 8]), v_weights[ex_bits]);
|
|
719
|
+
|
|
720
|
+
uint64_t lo64 = 0;
|
|
721
|
+
memcpy(&lo64, ex_code + (i / 8) * ex_bits, sizeof(uint64_t));
|
|
707
722
|
|
|
708
723
|
for (size_t b = 0; b < ex_bits; b++) {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
recon = _mm256_fmadd_ps(p_f, v_weights[b], recon);
|
|
724
|
+
const uint32_t plane =
|
|
725
|
+
static_cast<uint32_t>(_pext_u64(lo64, pext_masks[b]));
|
|
726
|
+
recon = _mm512_mask_add_ps(
|
|
727
|
+
recon, static_cast<__mmask16>(plane), recon, v_weights[b]);
|
|
714
728
|
}
|
|
715
729
|
|
|
716
|
-
|
|
717
|
-
acc =
|
|
730
|
+
__m512 rq = _mm512_maskz_loadu_ps(low8, rotated_q + i);
|
|
731
|
+
acc = _mm512_fmadd_ps(
|
|
732
|
+
rq, _mm512_mask_add_ps(recon, low8, recon, v_cb), acc);
|
|
733
|
+
i += 8;
|
|
718
734
|
}
|
|
719
735
|
|
|
720
|
-
float result =
|
|
736
|
+
float result = _mm512_reduce_add_ps(acc);
|
|
721
737
|
result += ip_scalar(sign_bits, ex_code, rotated_q, i, d, ex_bits, cb);
|
|
722
738
|
return result;
|
|
723
739
|
}
|
|
@@ -739,7 +755,8 @@ float compute_inner_product<SIMDLevel::AVX512>(
|
|
|
739
755
|
|
|
740
756
|
#ifdef __BMI2__
|
|
741
757
|
if (ex_bits <= 7) {
|
|
742
|
-
return
|
|
758
|
+
return ip_bitplane_avx512(
|
|
759
|
+
sign_bits, ex_code, rotated_q, d, ex_bits, cb);
|
|
743
760
|
}
|
|
744
761
|
#endif
|
|
745
762
|
return ip_scalar(sign_bits, ex_code, rotated_q, 0, d, ex_bits, cb);
|
|
@@ -6,34 +6,31 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @file
|
|
9
|
+
* @file rabitq_avx512_vpopcnt.cpp
|
|
10
10
|
*
|
|
11
|
-
* RaBitQ SIMD kernels specialized for SIMDLevel::
|
|
11
|
+
* RaBitQ SIMD kernels specialized for SIMDLevel::AVX512_VPOPCNT.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* multi-step shuffle
|
|
17
|
-
* specialization in rabitq_avx512.cpp.
|
|
18
|
-
* (bitwise_and_dot_product, bitwise_xor_dot_product, popcount) become
|
|
19
|
-
* substantially shorter and faster on SPR+ as a result.
|
|
13
|
+
* AVX-512 VPOPCNTDQ performs a per-lane 64-bit popcount in a single
|
|
14
|
+
* instruction. It is available on CPUs including Ice Lake, Zen 4, and
|
|
15
|
+
* Sapphire Rapids, independently of the other SPR-only extensions. This
|
|
16
|
+
* replaces the multi-step shuffle-based popcount used by the generic
|
|
17
|
+
* AVX-512 specialization in rabitq_avx512.cpp.
|
|
20
18
|
*
|
|
21
19
|
* Build / dispatch behavior:
|
|
22
20
|
* - faiss_avx512 (AVX-512 only, no SPR features): NOT compiled.
|
|
23
21
|
* The existing AVX512 specialization in rabitq_avx512.cpp is used.
|
|
24
|
-
* - faiss_avx512_spr
|
|
25
|
-
*
|
|
26
|
-
* selected by static dispatch.
|
|
22
|
+
* - faiss_avx512_spr: compiled alongside the full SPR specialization and
|
|
23
|
+
* selected through the SPR -> VPOPCNT fallback.
|
|
27
24
|
* - faiss with FAISS_OPT_LEVEL=dd (dynamic dispatch): compiled with
|
|
28
25
|
* -mavx512vpopcntdq as a per-file flag. Selected at runtime when
|
|
29
|
-
*
|
|
26
|
+
* the CPU exposes AVX512_VPOPCNTDQ.
|
|
30
27
|
*
|
|
31
28
|
* The floating-point multi-bit inner-product kernel does not benefit
|
|
32
|
-
* from VPOPCNTDQ, so this TU forwards compute_inner_product<
|
|
29
|
+
* from VPOPCNTDQ, so this TU forwards compute_inner_product<VPOPCNT> to
|
|
33
30
|
* the AVX512 implementation to avoid duplicating that code path.
|
|
34
31
|
*/
|
|
35
32
|
|
|
36
|
-
#ifdef
|
|
33
|
+
#ifdef COMPILE_SIMD_AVX512_VPOPCNT
|
|
37
34
|
|
|
38
35
|
#include <faiss/utils/popcount.h>
|
|
39
36
|
#include <faiss/utils/rabitq_simd.h>
|
|
@@ -47,7 +44,7 @@
|
|
|
47
44
|
namespace faiss::rabitq {
|
|
48
45
|
|
|
49
46
|
// Forward declarations for the AVX512 specializations defined in
|
|
50
|
-
// rabitq_avx512.cpp. They live in the same TU group
|
|
47
|
+
// rabitq_avx512.cpp. They live in the same TU group in supported builds, so
|
|
51
48
|
// we can reuse them as a tail handler / fallback. Declaring rather
|
|
52
49
|
// than redefining avoids ODR risk and keeps a single source of truth
|
|
53
50
|
// for the floating-point kernel.
|
|
@@ -75,8 +72,8 @@ inline __m512i popcount_512_vpopcntdq(__m512i v) {
|
|
|
75
72
|
}
|
|
76
73
|
|
|
77
74
|
// 256-bit popcount using AVX-512VL VPOPCNTDQ.
|
|
78
|
-
//
|
|
79
|
-
//
|
|
75
|
+
// Baseline AVX-512 includes AVX512VL, so VPOPCNTDQ is also available on
|
|
76
|
+
// 256-bit registers via _mm256_popcnt_epi64.
|
|
80
77
|
inline __m256i popcount_256_vpopcntdq(__m256i v) {
|
|
81
78
|
return _mm256_popcnt_epi64(v);
|
|
82
79
|
}
|
|
@@ -101,7 +98,7 @@ inline uint64_t reduce_add_128(__m128i v) {
|
|
|
101
98
|
} // namespace
|
|
102
99
|
|
|
103
100
|
template <>
|
|
104
|
-
uint64_t bitwise_and_dot_product<SIMDLevel::
|
|
101
|
+
uint64_t bitwise_and_dot_product<SIMDLevel::AVX512_VPOPCNT>(
|
|
105
102
|
const uint8_t* query,
|
|
106
103
|
const uint8_t* data,
|
|
107
104
|
size_t size,
|
|
@@ -187,7 +184,7 @@ uint64_t bitwise_and_dot_product<SIMDLevel::AVX512_SPR>(
|
|
|
187
184
|
|
|
188
185
|
template <>
|
|
189
186
|
BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
|
|
190
|
-
SIMDLevel::
|
|
187
|
+
SIMDLevel::AVX512_VPOPCNT>(
|
|
191
188
|
const uint8_t* query,
|
|
192
189
|
const uint8_t* data,
|
|
193
190
|
size_t size,
|
|
@@ -278,7 +275,7 @@ BitwiseAndDotProductResult bitwise_and_dot_product_with_popcount<
|
|
|
278
275
|
}
|
|
279
276
|
|
|
280
277
|
template <>
|
|
281
|
-
uint64_t bitwise_xor_dot_product<SIMDLevel::
|
|
278
|
+
uint64_t bitwise_xor_dot_product<SIMDLevel::AVX512_VPOPCNT>(
|
|
282
279
|
const uint8_t* query,
|
|
283
280
|
const uint8_t* data,
|
|
284
281
|
size_t size,
|
|
@@ -357,7 +354,7 @@ uint64_t bitwise_xor_dot_product<SIMDLevel::AVX512_SPR>(
|
|
|
357
354
|
}
|
|
358
355
|
|
|
359
356
|
template <>
|
|
360
|
-
uint64_t popcount<SIMDLevel::
|
|
357
|
+
uint64_t popcount<SIMDLevel::AVX512_VPOPCNT>(const uint8_t* data, size_t size) {
|
|
361
358
|
uint64_t sum = 0;
|
|
362
359
|
size_t offset = 0;
|
|
363
360
|
|
|
@@ -419,7 +416,7 @@ float compute_inner_product<SIMDLevel::AVX512>(
|
|
|
419
416
|
float cb);
|
|
420
417
|
|
|
421
418
|
template <>
|
|
422
|
-
float compute_inner_product<SIMDLevel::
|
|
419
|
+
float compute_inner_product<SIMDLevel::AVX512_VPOPCNT>(
|
|
423
420
|
const uint8_t* __restrict sign_bits,
|
|
424
421
|
const uint8_t* __restrict ex_code,
|
|
425
422
|
const float* __restrict rotated_q,
|
|
@@ -432,4 +429,4 @@ float compute_inner_product<SIMDLevel::AVX512_SPR>(
|
|
|
432
429
|
|
|
433
430
|
} // namespace faiss::rabitq::multibit
|
|
434
431
|
|
|
435
|
-
#endif //
|
|
432
|
+
#endif // COMPILE_SIMD_AVX512_VPOPCNT
|
|
@@ -9,13 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
// Private dispatch wrapper for SuperKMeans's block_l2. Routes to the
|
|
11
11
|
// highest available SIMD specialization at runtime (DD mode) or the
|
|
12
|
-
// compiled-in level (static mode).
|
|
13
|
-
// scalar primary template; adding NEON/SVE means just adding a new
|
|
14
|
-
// specialization file alongside the AVX ones.
|
|
12
|
+
// compiled-in level (static mode).
|
|
15
13
|
//
|
|
16
|
-
// Known perf gap: aarch64 (NEON/SVE) specializations are not implemented yet.
|
|
17
|
-
// aarch64 falls through to the scalar primary template. Validating SVE requires
|
|
18
|
-
// a Graviton-class host; deferred to a focused follow-up.
|
|
19
14
|
|
|
20
15
|
#include <faiss/impl/simd_dispatch.h>
|
|
21
16
|
#include <faiss/utils/simd_impl/super_kmeans_kernels.h>
|
|
@@ -24,7 +19,7 @@ namespace faiss {
|
|
|
24
19
|
namespace detail {
|
|
25
20
|
|
|
26
21
|
inline float block_l2_dispatch(const float* x, const float* y, int n) {
|
|
27
|
-
return
|
|
22
|
+
return with_simd_level_with_sve(
|
|
28
23
|
[&]<SIMDLevel SL>() { return block_l2<SL>(x, y, n); });
|
|
29
24
|
}
|
|
30
25
|
|
|
@@ -16,7 +16,7 @@ namespace detail {
|
|
|
16
16
|
|
|
17
17
|
// Squared L2 over `n` dimensions; n in [1, pdx_block_size].
|
|
18
18
|
// Primary template is the scalar fallback; SIMDLevels without a dedicated
|
|
19
|
-
// specialization (ARM_NEON,
|
|
19
|
+
// specialization (ARM_NEON, NONE, ...) use it directly.
|
|
20
20
|
template <SIMDLevel Level>
|
|
21
21
|
inline float block_l2(const float* x, const float* y, int n) {
|
|
22
22
|
float s = 0.0f;
|
|
@@ -39,5 +39,10 @@ template <>
|
|
|
39
39
|
float block_l2<SIMDLevel::AVX512>(const float* x, const float* y, int n);
|
|
40
40
|
#endif
|
|
41
41
|
|
|
42
|
+
#ifdef COMPILE_SIMD_ARM_SVE
|
|
43
|
+
template <>
|
|
44
|
+
float block_l2<SIMDLevel::ARM_SVE>(const float* x, const float* y, int n);
|
|
45
|
+
#endif
|
|
46
|
+
|
|
42
47
|
} // namespace detail
|
|
43
48
|
} // namespace faiss
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#ifdef COMPILE_SIMD_ARM_SVE
|
|
9
|
+
|
|
10
|
+
#include <faiss/utils/simd_impl/super_kmeans_kernels.h>
|
|
11
|
+
|
|
12
|
+
#include <arm_sve.h>
|
|
13
|
+
|
|
14
|
+
namespace faiss {
|
|
15
|
+
namespace detail {
|
|
16
|
+
|
|
17
|
+
template <>
|
|
18
|
+
float block_l2<SIMDLevel::ARM_SVE>(const float* x, const float* y, int n) {
|
|
19
|
+
svfloat32_t acc = svdup_n_f32(0.0f);
|
|
20
|
+
const int lanes = static_cast<int>(svcntw());
|
|
21
|
+
for (int m = 0; m < n; m += lanes) {
|
|
22
|
+
const svbool_t pg = svwhilelt_b32(m, n);
|
|
23
|
+
const svfloat32_t xv = svld1_f32(pg, x + m);
|
|
24
|
+
const svfloat32_t yv = svld1_f32(pg, y + m);
|
|
25
|
+
const svfloat32_t diff = svsub_f32_x(pg, xv, yv);
|
|
26
|
+
acc = svmla_f32_m(pg, acc, diff, diff);
|
|
27
|
+
}
|
|
28
|
+
return svaddv_f32(svptrue_b32(), acc);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
} // namespace detail
|
|
32
|
+
} // namespace faiss
|
|
33
|
+
|
|
34
|
+
#endif // COMPILE_SIMD_ARM_SVE
|