Coverage Report

Created: 2026-10-12 17:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
contrib/faiss/faiss/utils/distances_fused/simdlib_based.cpp
Line
Count
Source
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
// -*- c++ -*-
9
10
#include <faiss/utils/distances_fused/simdlib_based.h>
11
12
#if defined(__AVX2__) || defined(__aarch64__)
13
14
#include <faiss/utils/simdlib.h>
15
16
#if defined(__AVX2__)
17
#include <immintrin.h>
18
#endif
19
20
namespace faiss {
21
22
namespace {
23
24
// It makes sense to like to overload certain cases because the further
25
// kernels are in need of registers. So, let's tell compiler
26
// not to waste registers on a bit faster code, if needed.
27
template <size_t DIM>
28
6.48k
float l2_sqr(const float* const x) {
29
    // compiler should be smart enough to handle that
30
6.48k
    float output = x[0] * x[0];
31
28.7k
    for (size_t i = 1; i < DIM; i++) {
32
22.2k
        output += x[i] * x[i];
33
22.2k
    }
34
35
6.48k
    return output;
36
6.48k
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm1EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm2EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm3EEEfPKf
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm4EEEfPKf
Line
Count
Source
28
5.03k
float l2_sqr(const float* const x) {
29
    // compiler should be smart enough to handle that
30
5.03k
    float output = x[0] * x[0];
31
20.1k
    for (size_t i = 1; i < DIM; i++) {
32
15.1k
        output += x[i] * x[i];
33
15.1k
    }
34
35
5.03k
    return output;
36
5.03k
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm5EEEfPKf
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm6EEEfPKf
Line
Count
Source
28
1.44k
float l2_sqr(const float* const x) {
29
    // compiler should be smart enough to handle that
30
1.44k
    float output = x[0] * x[0];
31
8.62k
    for (size_t i = 1; i < DIM; i++) {
32
7.17k
        output += x[i] * x[i];
33
7.17k
    }
34
35
1.44k
    return output;
36
1.44k
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm7EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm8EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm9EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm10EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm11EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm12EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm13EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm14EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm15EEEfPKf
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16l2_sqrILm16EEEfPKf
37
38
template <size_t DIM>
39
float dot_product(
40
        const float* const __restrict x,
41
22.1k
        const float* const __restrict y) {
42
    // compiler should be smart enough to handle that
43
22.1k
    float output = x[0] * y[0];
44
97.6k
    for (size_t i = 1; i < DIM; i++) {
45
75.5k
        output += x[i] * y[i];
46
75.5k
    }
47
48
22.1k
    return output;
49
22.1k
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm1EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm2EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm3EEEfPKfS3_
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm4EEEfPKfS3_
Line
Count
Source
41
17.4k
        const float* const __restrict y) {
42
    // compiler should be smart enough to handle that
43
17.4k
    float output = x[0] * y[0];
44
70.0k
    for (size_t i = 1; i < DIM; i++) {
45
52.5k
        output += x[i] * y[i];
46
52.5k
    }
47
48
17.4k
    return output;
49
17.4k
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm5EEEfPKfS3_
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm6EEEfPKfS3_
Line
Count
Source
41
4.63k
        const float* const __restrict y) {
42
    // compiler should be smart enough to handle that
43
4.63k
    float output = x[0] * y[0];
44
27.5k
    for (size_t i = 1; i < DIM; i++) {
45
22.9k
        output += x[i] * y[i];
46
22.9k
    }
47
48
4.63k
    return output;
49
4.63k
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm7EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm8EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm9EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm10EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm11EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm12EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm13EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm14EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm15EEEfPKfS3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_111dot_productILm16EEEfPKfS3_
50
51
// The kernel for low dimensionality vectors.
52
// Finds the closest one from y for every given NX_POINTS_PER_LOOP points from x
53
//
54
// DIM is the dimensionality of the data
55
// NX_POINTS_PER_LOOP is the number of x points that get processed
56
//   simultaneously.
57
// NY_POINTS_PER_LOOP is the number of y points that get processed
58
//   simultaneously.
59
template <size_t DIM, size_t NX_POINTS_PER_LOOP, size_t NY_POINTS_PER_LOOP>
60
void kernel(
61
        const float* const __restrict x,
62
        const float* const __restrict y,
63
        const float* const __restrict y_transposed,
64
        const size_t ny,
65
        Top1BlockResultHandler<CMax<float, int64_t>>& res,
66
        const float* __restrict y_norms,
67
809
        const size_t i) {
68
809
    const size_t ny_p =
69
809
            (ny / (8 * NY_POINTS_PER_LOOP)) * (8 * NY_POINTS_PER_LOOP);
70
71
    // compute
72
809
    const float* const __restrict xd_0 = x + i * DIM;
73
74
    // prefetch the next point
75
809
#if defined(__AVX2__)
76
809
    _mm_prefetch((const char*)(xd_0 + DIM * sizeof(float)), _MM_HINT_NTA);
77
809
#endif
78
79
    // load a single point from x
80
    // load -2 * value
81
809
    simd8float32 x_i[NX_POINTS_PER_LOOP][DIM];
82
6.75k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
83
30.0k
        for (size_t dd = 0; dd < DIM; dd++) {
84
24.0k
            x_i[nx_k][dd] = simd8float32(-2 * *(xd_0 + nx_k * DIM + dd));
85
24.0k
        }
86
5.94k
    }
87
88
    // compute x_norm
89
809
    float x_norm_i[NX_POINTS_PER_LOOP];
90
6.90k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
91
6.09k
        x_norm_i[nx_k] = l2_sqr<DIM>(xd_0 + nx_k * DIM);
92
6.09k
    }
93
94
    // distances and indices
95
809
    simd8float32 min_distances_i[NX_POINTS_PER_LOOP];
96
6.81k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
97
6.00k
        min_distances_i[nx_k] =
98
6.00k
                simd8float32(res.dis_tab[i + nx_k] - x_norm_i[nx_k]);
99
6.00k
    }
100
101
809
    simd8uint32 min_indices_i[NX_POINTS_PER_LOOP];
102
6.79k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
103
5.98k
        min_indices_i[nx_k] = simd8uint32((uint32_t)0);
104
5.98k
    }
105
106
    //
107
809
    simd8uint32 current_indices = simd8uint32(0, 1, 2, 3, 4, 5, 6, 7);
108
809
    const simd8uint32 indices_delta = simd8uint32(8);
109
110
    // main loop
111
809
    size_t j = 0;
112
809
    for (; j < ny_p; j += NY_POINTS_PER_LOOP * 8) {
113
        // compute dot products for NX_POINTS from x and NY_POINTS from y
114
        // technically, we're multiplying -2x and y
115
0
        simd8float32 dp_i[NX_POINTS_PER_LOOP][NY_POINTS_PER_LOOP];
116
117
        // DIM 0 that uses MUL
118
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
119
0
            simd8float32 y_i =
120
0
                    simd8float32(y_transposed + j + ny_k * 8 + ny * 0);
121
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
122
0
                dp_i[nx_k][ny_k] = x_i[nx_k][0] * y_i;
123
0
            }
124
0
        }
125
126
        // other DIMs that use FMA
127
0
        for (size_t dd = 1; dd < DIM; dd++) {
128
0
            for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
129
0
                simd8float32 y_i =
130
0
                        simd8float32(y_transposed + j + ny_k * 8 + ny * dd);
131
132
0
                for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
133
0
                    dp_i[nx_k][ny_k] =
134
0
                            fmadd(x_i[nx_k][dd], y_i, dp_i[nx_k][ny_k]);
135
0
                }
136
0
            }
137
0
        }
138
139
        // compute y^2 + (-2x,y)
140
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
141
0
            simd8float32 y_l2_sqr = simd8float32(y_norms + j + ny_k * 8);
142
143
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
144
0
                dp_i[nx_k][ny_k] = dp_i[nx_k][ny_k] + y_l2_sqr;
145
0
            }
146
0
        }
147
148
        // do the comparisons and alter the min indices
149
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
150
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
151
                // cmpps
152
0
                cmplt_and_blend_inplace(
153
0
                        dp_i[nx_k][ny_k],
154
0
                        current_indices,
155
0
                        min_distances_i[nx_k],
156
0
                        min_indices_i[nx_k]);
157
0
            }
158
159
0
            current_indices = current_indices + indices_delta;
160
0
        }
161
0
    }
162
163
    // dump values and find the minimum distance / minimum index
164
6.75k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
165
5.94k
        float min_distances_scalar[8];
166
5.94k
        uint32_t min_indices_scalar[8];
167
168
5.94k
        min_distances_i[nx_k].storeu(min_distances_scalar);
169
5.94k
        min_indices_i[nx_k].storeu(min_indices_scalar);
170
171
5.94k
        float current_min_distance = res.dis_tab[i + nx_k];
172
5.94k
        uint32_t current_min_index = res.ids_tab[i + nx_k];
173
174
        // This unusual comparison is needed to maintain the behavior
175
        // of the original implementation: if two indices are
176
        // represented with equal distance values, then
177
        // the index with the min value is returned.
178
50.9k
        for (size_t jv = 0; jv < 8; jv++) {
179
            // add missing x_norms[i]
180
45.0k
            float distance_candidate =
181
45.0k
                    min_distances_scalar[jv] + x_norm_i[nx_k];
182
183
            // negative values can occur for identical vectors
184
            //    due to roundoff errors.
185
45.0k
            if (distance_candidate < 0) {
186
0
                distance_candidate = 0;
187
0
            }
188
189
45.0k
            const int64_t index_candidate = min_indices_scalar[jv];
190
191
45.0k
            if (current_min_distance > distance_candidate) {
192
0
                current_min_distance = distance_candidate;
193
0
                current_min_index = index_candidate;
194
45.0k
            } else if (
195
45.0k
                    current_min_distance == distance_candidate &&
196
45.0k
                    current_min_index > index_candidate) {
197
4.82k
                current_min_index = index_candidate;
198
4.82k
            }
199
45.0k
        }
200
201
        // process leftovers
202
28.3k
        for (size_t j0 = j; j0 < ny; j0++) {
203
22.3k
            const float dp =
204
22.3k
                    dot_product<DIM>(x + (i + nx_k) * DIM, y + j0 * DIM);
205
22.3k
            float dis = x_norm_i[nx_k] + y_norms[j0] - 2 * dp;
206
            // negative values can occur for identical vectors
207
            //    due to roundoff errors.
208
22.3k
            if (dis < 0) {
209
28
                dis = 0;
210
28
            }
211
212
22.3k
            if (current_min_distance > dis) {
213
12.1k
                current_min_distance = dis;
214
12.1k
                current_min_index = j0;
215
12.1k
            }
216
22.3k
        }
217
218
        // done
219
5.94k
        res.add_result(i + nx_k, current_min_distance, current_min_index);
220
5.94k
    }
221
809
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm1ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm1ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm2ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm2ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm3ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm3ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm4ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Line
Count
Source
67
613
        const size_t i) {
68
613
    const size_t ny_p =
69
613
            (ny / (8 * NY_POINTS_PER_LOOP)) * (8 * NY_POINTS_PER_LOOP);
70
71
    // compute
72
613
    const float* const __restrict xd_0 = x + i * DIM;
73
74
    // prefetch the next point
75
613
#if defined(__AVX2__)
76
613
    _mm_prefetch((const char*)(xd_0 + DIM * sizeof(float)), _MM_HINT_NTA);
77
613
#endif
78
79
    // load a single point from x
80
    // load -2 * value
81
613
    simd8float32 x_i[NX_POINTS_PER_LOOP][DIM];
82
5.21k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
83
21.6k
        for (size_t dd = 0; dd < DIM; dd++) {
84
17.0k
            x_i[nx_k][dd] = simd8float32(-2 * *(xd_0 + nx_k * DIM + dd));
85
17.0k
        }
86
4.60k
    }
87
88
    // compute x_norm
89
613
    float x_norm_i[NX_POINTS_PER_LOOP];
90
5.34k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
91
4.73k
        x_norm_i[nx_k] = l2_sqr<DIM>(xd_0 + nx_k * DIM);
92
4.73k
    }
93
94
    // distances and indices
95
613
    simd8float32 min_distances_i[NX_POINTS_PER_LOOP];
96
5.29k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
97
4.68k
        min_distances_i[nx_k] =
98
4.68k
                simd8float32(res.dis_tab[i + nx_k] - x_norm_i[nx_k]);
99
4.68k
    }
100
101
613
    simd8uint32 min_indices_i[NX_POINTS_PER_LOOP];
102
5.29k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
103
4.67k
        min_indices_i[nx_k] = simd8uint32((uint32_t)0);
104
4.67k
    }
105
106
    //
107
613
    simd8uint32 current_indices = simd8uint32(0, 1, 2, 3, 4, 5, 6, 7);
108
613
    const simd8uint32 indices_delta = simd8uint32(8);
109
110
    // main loop
111
613
    size_t j = 0;
112
613
    for (; j < ny_p; j += NY_POINTS_PER_LOOP * 8) {
113
        // compute dot products for NX_POINTS from x and NY_POINTS from y
114
        // technically, we're multiplying -2x and y
115
0
        simd8float32 dp_i[NX_POINTS_PER_LOOP][NY_POINTS_PER_LOOP];
116
117
        // DIM 0 that uses MUL
118
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
119
0
            simd8float32 y_i =
120
0
                    simd8float32(y_transposed + j + ny_k * 8 + ny * 0);
121
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
122
0
                dp_i[nx_k][ny_k] = x_i[nx_k][0] * y_i;
123
0
            }
124
0
        }
125
126
        // other DIMs that use FMA
127
0
        for (size_t dd = 1; dd < DIM; dd++) {
128
0
            for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
129
0
                simd8float32 y_i =
130
0
                        simd8float32(y_transposed + j + ny_k * 8 + ny * dd);
131
132
0
                for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
133
0
                    dp_i[nx_k][ny_k] =
134
0
                            fmadd(x_i[nx_k][dd], y_i, dp_i[nx_k][ny_k]);
135
0
                }
136
0
            }
137
0
        }
138
139
        // compute y^2 + (-2x,y)
140
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
141
0
            simd8float32 y_l2_sqr = simd8float32(y_norms + j + ny_k * 8);
142
143
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
144
0
                dp_i[nx_k][ny_k] = dp_i[nx_k][ny_k] + y_l2_sqr;
145
0
            }
146
0
        }
147
148
        // do the comparisons and alter the min indices
149
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
150
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
151
                // cmpps
152
0
                cmplt_and_blend_inplace(
153
0
                        dp_i[nx_k][ny_k],
154
0
                        current_indices,
155
0
                        min_distances_i[nx_k],
156
0
                        min_indices_i[nx_k]);
157
0
            }
158
159
0
            current_indices = current_indices + indices_delta;
160
0
        }
161
0
    }
162
163
    // dump values and find the minimum distance / minimum index
164
5.23k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
165
4.62k
        float min_distances_scalar[8];
166
4.62k
        uint32_t min_indices_scalar[8];
167
168
4.62k
        min_distances_i[nx_k].storeu(min_distances_scalar);
169
4.62k
        min_indices_i[nx_k].storeu(min_indices_scalar);
170
171
4.62k
        float current_min_distance = res.dis_tab[i + nx_k];
172
4.62k
        uint32_t current_min_index = res.ids_tab[i + nx_k];
173
174
        // This unusual comparison is needed to maintain the behavior
175
        // of the original implementation: if two indices are
176
        // represented with equal distance values, then
177
        // the index with the min value is returned.
178
40.2k
        for (size_t jv = 0; jv < 8; jv++) {
179
            // add missing x_norms[i]
180
35.6k
            float distance_candidate =
181
35.6k
                    min_distances_scalar[jv] + x_norm_i[nx_k];
182
183
            // negative values can occur for identical vectors
184
            //    due to roundoff errors.
185
35.6k
            if (distance_candidate < 0) {
186
0
                distance_candidate = 0;
187
0
            }
188
189
35.6k
            const int64_t index_candidate = min_indices_scalar[jv];
190
191
35.6k
            if (current_min_distance > distance_candidate) {
192
0
                current_min_distance = distance_candidate;
193
0
                current_min_index = index_candidate;
194
35.6k
            } else if (
195
35.6k
                    current_min_distance == distance_candidate &&
196
35.7k
                    current_min_index > index_candidate) {
197
3.85k
                current_min_index = index_candidate;
198
3.85k
            }
199
35.6k
        }
200
201
        // process leftovers
202
22.2k
        for (size_t j0 = j; j0 < ny; j0++) {
203
17.6k
            const float dp =
204
17.6k
                    dot_product<DIM>(x + (i + nx_k) * DIM, y + j0 * DIM);
205
17.6k
            float dis = x_norm_i[nx_k] + y_norms[j0] - 2 * dp;
206
            // negative values can occur for identical vectors
207
            //    due to roundoff errors.
208
17.6k
            if (dis < 0) {
209
28
                dis = 0;
210
28
            }
211
212
17.6k
            if (current_min_distance > dis) {
213
9.68k
                current_min_distance = dis;
214
9.68k
                current_min_index = j0;
215
9.68k
            }
216
17.6k
        }
217
218
        // done
219
4.62k
        res.add_result(i + nx_k, current_min_distance, current_min_index);
220
4.62k
    }
221
613
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm4ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm5ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm5ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm6ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Line
Count
Source
67
174
        const size_t i) {
68
174
    const size_t ny_p =
69
174
            (ny / (8 * NY_POINTS_PER_LOOP)) * (8 * NY_POINTS_PER_LOOP);
70
71
    // compute
72
174
    const float* const __restrict xd_0 = x + i * DIM;
73
74
    // prefetch the next point
75
174
#if defined(__AVX2__)
76
174
    _mm_prefetch((const char*)(xd_0 + DIM * sizeof(float)), _MM_HINT_NTA);
77
174
#endif
78
79
    // load a single point from x
80
    // load -2 * value
81
174
    simd8float32 x_i[NX_POINTS_PER_LOOP][DIM];
82
1.49k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
83
8.17k
        for (size_t dd = 0; dd < DIM; dd++) {
84
6.84k
            x_i[nx_k][dd] = simd8float32(-2 * *(xd_0 + nx_k * DIM + dd));
85
6.84k
        }
86
1.32k
    }
87
88
    // compute x_norm
89
174
    float x_norm_i[NX_POINTS_PER_LOOP];
90
1.51k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
91
1.33k
        x_norm_i[nx_k] = l2_sqr<DIM>(xd_0 + nx_k * DIM);
92
1.33k
    }
93
94
    // distances and indices
95
174
    simd8float32 min_distances_i[NX_POINTS_PER_LOOP];
96
1.47k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
97
1.29k
        min_distances_i[nx_k] =
98
1.29k
                simd8float32(res.dis_tab[i + nx_k] - x_norm_i[nx_k]);
99
1.29k
    }
100
101
174
    simd8uint32 min_indices_i[NX_POINTS_PER_LOOP];
102
1.45k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
103
1.28k
        min_indices_i[nx_k] = simd8uint32((uint32_t)0);
104
1.28k
    }
105
106
    //
107
174
    simd8uint32 current_indices = simd8uint32(0, 1, 2, 3, 4, 5, 6, 7);
108
174
    const simd8uint32 indices_delta = simd8uint32(8);
109
110
    // main loop
111
174
    size_t j = 0;
112
174
    for (; j < ny_p; j += NY_POINTS_PER_LOOP * 8) {
113
        // compute dot products for NX_POINTS from x and NY_POINTS from y
114
        // technically, we're multiplying -2x and y
115
0
        simd8float32 dp_i[NX_POINTS_PER_LOOP][NY_POINTS_PER_LOOP];
116
117
        // DIM 0 that uses MUL
118
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
119
0
            simd8float32 y_i =
120
0
                    simd8float32(y_transposed + j + ny_k * 8 + ny * 0);
121
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
122
0
                dp_i[nx_k][ny_k] = x_i[nx_k][0] * y_i;
123
0
            }
124
0
        }
125
126
        // other DIMs that use FMA
127
0
        for (size_t dd = 1; dd < DIM; dd++) {
128
0
            for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
129
0
                simd8float32 y_i =
130
0
                        simd8float32(y_transposed + j + ny_k * 8 + ny * dd);
131
132
0
                for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
133
0
                    dp_i[nx_k][ny_k] =
134
0
                            fmadd(x_i[nx_k][dd], y_i, dp_i[nx_k][ny_k]);
135
0
                }
136
0
            }
137
0
        }
138
139
        // compute y^2 + (-2x,y)
140
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
141
0
            simd8float32 y_l2_sqr = simd8float32(y_norms + j + ny_k * 8);
142
143
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
144
0
                dp_i[nx_k][ny_k] = dp_i[nx_k][ny_k] + y_l2_sqr;
145
0
            }
146
0
        }
147
148
        // do the comparisons and alter the min indices
149
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
150
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
151
                // cmpps
152
0
                cmplt_and_blend_inplace(
153
0
                        dp_i[nx_k][ny_k],
154
0
                        current_indices,
155
0
                        min_distances_i[nx_k],
156
0
                        min_indices_i[nx_k]);
157
0
            }
158
159
0
            current_indices = current_indices + indices_delta;
160
0
        }
161
0
    }
162
163
    // dump values and find the minimum distance / minimum index
164
1.47k
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
165
1.29k
        float min_distances_scalar[8];
166
1.29k
        uint32_t min_indices_scalar[8];
167
168
1.29k
        min_distances_i[nx_k].storeu(min_distances_scalar);
169
1.29k
        min_indices_i[nx_k].storeu(min_indices_scalar);
170
171
1.29k
        float current_min_distance = res.dis_tab[i + nx_k];
172
1.29k
        uint32_t current_min_index = res.ids_tab[i + nx_k];
173
174
        // This unusual comparison is needed to maintain the behavior
175
        // of the original implementation: if two indices are
176
        // represented with equal distance values, then
177
        // the index with the min value is returned.
178
10.5k
        for (size_t jv = 0; jv < 8; jv++) {
179
            // add missing x_norms[i]
180
9.21k
            float distance_candidate =
181
9.21k
                    min_distances_scalar[jv] + x_norm_i[nx_k];
182
183
            // negative values can occur for identical vectors
184
            //    due to roundoff errors.
185
9.21k
            if (distance_candidate < 0) {
186
0
                distance_candidate = 0;
187
0
            }
188
189
9.21k
            const int64_t index_candidate = min_indices_scalar[jv];
190
191
9.21k
            if (current_min_distance > distance_candidate) {
192
0
                current_min_distance = distance_candidate;
193
0
                current_min_index = index_candidate;
194
9.21k
            } else if (
195
9.21k
                    current_min_distance == distance_candidate &&
196
9.21k
                    current_min_index > index_candidate) {
197
970
                current_min_index = index_candidate;
198
970
            }
199
9.21k
        }
200
201
        // process leftovers
202
5.95k
        for (size_t j0 = j; j0 < ny; j0++) {
203
4.65k
            const float dp =
204
4.65k
                    dot_product<DIM>(x + (i + nx_k) * DIM, y + j0 * DIM);
205
4.65k
            float dis = x_norm_i[nx_k] + y_norms[j0] - 2 * dp;
206
            // negative values can occur for identical vectors
207
            //    due to roundoff errors.
208
4.65k
            if (dis < 0) {
209
0
                dis = 0;
210
0
            }
211
212
4.65k
            if (current_min_distance > dis) {
213
2.42k
                current_min_distance = dis;
214
2.42k
                current_min_index = j0;
215
2.42k
            }
216
4.65k
        }
217
218
        // done
219
1.29k
        res.add_result(i + nx_k, current_min_distance, current_min_index);
220
1.29k
    }
221
174
}
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm6ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Line
Count
Source
67
22
        const size_t i) {
68
22
    const size_t ny_p =
69
22
            (ny / (8 * NY_POINTS_PER_LOOP)) * (8 * NY_POINTS_PER_LOOP);
70
71
    // compute
72
22
    const float* const __restrict xd_0 = x + i * DIM;
73
74
    // prefetch the next point
75
22
#if defined(__AVX2__)
76
22
    _mm_prefetch((const char*)(xd_0 + DIM * sizeof(float)), _MM_HINT_NTA);
77
22
#endif
78
79
    // load a single point from x
80
    // load -2 * value
81
22
    simd8float32 x_i[NX_POINTS_PER_LOOP][DIM];
82
44
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
83
154
        for (size_t dd = 0; dd < DIM; dd++) {
84
132
            x_i[nx_k][dd] = simd8float32(-2 * *(xd_0 + nx_k * DIM + dd));
85
132
        }
86
22
    }
87
88
    // compute x_norm
89
22
    float x_norm_i[NX_POINTS_PER_LOOP];
90
44
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
91
22
        x_norm_i[nx_k] = l2_sqr<DIM>(xd_0 + nx_k * DIM);
92
22
    }
93
94
    // distances and indices
95
22
    simd8float32 min_distances_i[NX_POINTS_PER_LOOP];
96
44
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
97
22
        min_distances_i[nx_k] =
98
22
                simd8float32(res.dis_tab[i + nx_k] - x_norm_i[nx_k]);
99
22
    }
100
101
22
    simd8uint32 min_indices_i[NX_POINTS_PER_LOOP];
102
44
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
103
22
        min_indices_i[nx_k] = simd8uint32((uint32_t)0);
104
22
    }
105
106
    //
107
22
    simd8uint32 current_indices = simd8uint32(0, 1, 2, 3, 4, 5, 6, 7);
108
22
    const simd8uint32 indices_delta = simd8uint32(8);
109
110
    // main loop
111
22
    size_t j = 0;
112
22
    for (; j < ny_p; j += NY_POINTS_PER_LOOP * 8) {
113
        // compute dot products for NX_POINTS from x and NY_POINTS from y
114
        // technically, we're multiplying -2x and y
115
0
        simd8float32 dp_i[NX_POINTS_PER_LOOP][NY_POINTS_PER_LOOP];
116
117
        // DIM 0 that uses MUL
118
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
119
0
            simd8float32 y_i =
120
0
                    simd8float32(y_transposed + j + ny_k * 8 + ny * 0);
121
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
122
0
                dp_i[nx_k][ny_k] = x_i[nx_k][0] * y_i;
123
0
            }
124
0
        }
125
126
        // other DIMs that use FMA
127
0
        for (size_t dd = 1; dd < DIM; dd++) {
128
0
            for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
129
0
                simd8float32 y_i =
130
0
                        simd8float32(y_transposed + j + ny_k * 8 + ny * dd);
131
132
0
                for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
133
0
                    dp_i[nx_k][ny_k] =
134
0
                            fmadd(x_i[nx_k][dd], y_i, dp_i[nx_k][ny_k]);
135
0
                }
136
0
            }
137
0
        }
138
139
        // compute y^2 + (-2x,y)
140
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
141
0
            simd8float32 y_l2_sqr = simd8float32(y_norms + j + ny_k * 8);
142
143
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
144
0
                dp_i[nx_k][ny_k] = dp_i[nx_k][ny_k] + y_l2_sqr;
145
0
            }
146
0
        }
147
148
        // do the comparisons and alter the min indices
149
0
        for (size_t ny_k = 0; ny_k < NY_POINTS_PER_LOOP; ny_k++) {
150
0
            for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
151
                // cmpps
152
0
                cmplt_and_blend_inplace(
153
0
                        dp_i[nx_k][ny_k],
154
0
                        current_indices,
155
0
                        min_distances_i[nx_k],
156
0
                        min_indices_i[nx_k]);
157
0
            }
158
159
0
            current_indices = current_indices + indices_delta;
160
0
        }
161
0
    }
162
163
    // dump values and find the minimum distance / minimum index
164
44
    for (size_t nx_k = 0; nx_k < NX_POINTS_PER_LOOP; nx_k++) {
165
22
        float min_distances_scalar[8];
166
22
        uint32_t min_indices_scalar[8];
167
168
22
        min_distances_i[nx_k].storeu(min_distances_scalar);
169
22
        min_indices_i[nx_k].storeu(min_indices_scalar);
170
171
22
        float current_min_distance = res.dis_tab[i + nx_k];
172
22
        uint32_t current_min_index = res.ids_tab[i + nx_k];
173
174
        // This unusual comparison is needed to maintain the behavior
175
        // of the original implementation: if two indices are
176
        // represented with equal distance values, then
177
        // the index with the min value is returned.
178
198
        for (size_t jv = 0; jv < 8; jv++) {
179
            // add missing x_norms[i]
180
176
            float distance_candidate =
181
176
                    min_distances_scalar[jv] + x_norm_i[nx_k];
182
183
            // negative values can occur for identical vectors
184
            //    due to roundoff errors.
185
176
            if (distance_candidate < 0) {
186
0
                distance_candidate = 0;
187
0
            }
188
189
176
            const int64_t index_candidate = min_indices_scalar[jv];
190
191
176
            if (current_min_distance > distance_candidate) {
192
0
                current_min_distance = distance_candidate;
193
0
                current_min_index = index_candidate;
194
176
            } else if (
195
176
                    current_min_distance == distance_candidate &&
196
176
                    current_min_index > index_candidate) {
197
4
                current_min_index = index_candidate;
198
4
            }
199
176
        }
200
201
        // process leftovers
202
110
        for (size_t j0 = j; j0 < ny; j0++) {
203
88
            const float dp =
204
88
                    dot_product<DIM>(x + (i + nx_k) * DIM, y + j0 * DIM);
205
88
            float dis = x_norm_i[nx_k] + y_norms[j0] - 2 * dp;
206
            // negative values can occur for identical vectors
207
            //    due to roundoff errors.
208
88
            if (dis < 0) {
209
0
                dis = 0;
210
0
            }
211
212
88
            if (current_min_distance > dis) {
213
22
                current_min_distance = dis;
214
22
                current_min_index = j0;
215
22
            }
216
88
        }
217
218
        // done
219
22
        res.add_result(i + nx_k, current_min_distance, current_min_index);
220
22
    }
221
22
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm7ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm7ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm8ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm8ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm9ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm9ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm10ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm10ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm11ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm11ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm12ELm8ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm12ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm13ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm13ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm14ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm14ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm15ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm15ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm16ELm6ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_16kernelILm16ELm1ELm1EEEvPKfS3_S3_mRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_m
222
223
template <size_t DIM, size_t NX_POINTS_PER_LOOP, size_t NY_POINTS_PER_LOOP>
224
void exhaustive_L2sqr_fused_cmax(
225
        const float* const __restrict x,
226
        const float* const __restrict y,
227
        size_t nx,
228
        size_t ny,
229
        Top1BlockResultHandler<CMax<float, int64_t>>& res,
230
99
        const float* __restrict y_norms) {
231
    // BLAS does not like empty matrices
232
99
    if (nx == 0 || ny == 0) {
233
0
        return;
234
0
    }
235
236
    // compute norms for y
237
99
    std::unique_ptr<float[]> del2;
238
99
    if (!y_norms) {
239
99
        float* y_norms2 = new float[ny];
240
99
        del2.reset(y_norms2);
241
242
495
        for (size_t i = 0; i < ny; i++) {
243
396
            y_norms2[i] = l2_sqr<DIM>(y + i * DIM);
244
396
        }
245
246
99
        y_norms = y_norms2;
247
99
    }
248
249
    // initialize res
250
99
    res.begin_multiple(0, nx);
251
252
    // transpose y
253
99
    std::vector<float> y_transposed(DIM * ny);
254
539
    for (size_t j = 0; j < DIM; j++) {
255
2.20k
        for (size_t i = 0; i < ny; i++) {
256
1.76k
            y_transposed[j * ny + i] = y[j + i * DIM];
257
1.76k
        }
258
440
    }
259
260
99
    const size_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
261
    // the main loop.
262
99
#pragma omp parallel for schedule(dynamic)
263
448
    for (size_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
264
224
        kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
265
224
                x, y, y_transposed.data(), ny, res, y_norms, i);
266
224
    }
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm1ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm2ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm3ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm4ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Line
Count
Source
263
376
    for (size_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
264
188
        kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
265
188
                x, y, y_transposed.data(), ny, res, y_norms, i);
266
188
    }
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm5ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm6ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Line
Count
Source
263
72
    for (size_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
264
36
        kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
265
36
                x, y, y_transposed.data(), ny, res, y_norms, i);
266
36
    }
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm7ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm8ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm9ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm10ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm11ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm12ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm13ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm14ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm15ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm16ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_.omp_outlined
267
268
121
    for (size_t i = nx_p; i < nx; i++) {
269
22
        kernel<DIM, 1, NY_POINTS_PER_LOOP>(
270
22
                x, y, y_transposed.data(), ny, res, y_norms, i);
271
22
    }
272
273
    // Does nothing for Top1BlockResultHandler, but
274
    // keeping the call for the consistency.
275
99
    res.end_multiple();
276
99
    InterruptCallback::check();
277
99
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm1ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm2ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm3ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm4ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Line
Count
Source
230
77
        const float* __restrict y_norms) {
231
    // BLAS does not like empty matrices
232
77
    if (nx == 0 || ny == 0) {
233
0
        return;
234
0
    }
235
236
    // compute norms for y
237
77
    std::unique_ptr<float[]> del2;
238
77
    if (!y_norms) {
239
77
        float* y_norms2 = new float[ny];
240
77
        del2.reset(y_norms2);
241
242
385
        for (size_t i = 0; i < ny; i++) {
243
308
            y_norms2[i] = l2_sqr<DIM>(y + i * DIM);
244
308
        }
245
246
77
        y_norms = y_norms2;
247
77
    }
248
249
    // initialize res
250
77
    res.begin_multiple(0, nx);
251
252
    // transpose y
253
77
    std::vector<float> y_transposed(DIM * ny);
254
385
    for (size_t j = 0; j < DIM; j++) {
255
1.54k
        for (size_t i = 0; i < ny; i++) {
256
1.23k
            y_transposed[j * ny + i] = y[j + i * DIM];
257
1.23k
        }
258
308
    }
259
260
77
    const size_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
261
    // the main loop.
262
77
#pragma omp parallel for schedule(dynamic)
263
77
    for (size_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
264
77
        kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
265
77
                x, y, y_transposed.data(), ny, res, y_norms, i);
266
77
    }
267
268
77
    for (size_t i = nx_p; i < nx; i++) {
269
0
        kernel<DIM, 1, NY_POINTS_PER_LOOP>(
270
0
                x, y, y_transposed.data(), ny, res, y_norms, i);
271
0
    }
272
273
    // Does nothing for Top1BlockResultHandler, but
274
    // keeping the call for the consistency.
275
77
    res.end_multiple();
276
77
    InterruptCallback::check();
277
77
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm5ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm6ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Line
Count
Source
230
22
        const float* __restrict y_norms) {
231
    // BLAS does not like empty matrices
232
22
    if (nx == 0 || ny == 0) {
233
0
        return;
234
0
    }
235
236
    // compute norms for y
237
22
    std::unique_ptr<float[]> del2;
238
22
    if (!y_norms) {
239
22
        float* y_norms2 = new float[ny];
240
22
        del2.reset(y_norms2);
241
242
110
        for (size_t i = 0; i < ny; i++) {
243
88
            y_norms2[i] = l2_sqr<DIM>(y + i * DIM);
244
88
        }
245
246
22
        y_norms = y_norms2;
247
22
    }
248
249
    // initialize res
250
22
    res.begin_multiple(0, nx);
251
252
    // transpose y
253
22
    std::vector<float> y_transposed(DIM * ny);
254
154
    for (size_t j = 0; j < DIM; j++) {
255
660
        for (size_t i = 0; i < ny; i++) {
256
528
            y_transposed[j * ny + i] = y[j + i * DIM];
257
528
        }
258
132
    }
259
260
22
    const size_t nx_p = (nx / NX_POINTS_PER_LOOP) * NX_POINTS_PER_LOOP;
261
    // the main loop.
262
22
#pragma omp parallel for schedule(dynamic)
263
22
    for (size_t i = 0; i < nx_p; i += NX_POINTS_PER_LOOP) {
264
22
        kernel<DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP>(
265
22
                x, y, y_transposed.data(), ny, res, y_norms, i);
266
22
    }
267
268
44
    for (size_t i = nx_p; i < nx; i++) {
269
22
        kernel<DIM, 1, NY_POINTS_PER_LOOP>(
270
22
                x, y, y_transposed.data(), ny, res, y_norms, i);
271
22
    }
272
273
    // Does nothing for Top1BlockResultHandler, but
274
    // keeping the call for the consistency.
275
22
    res.end_multiple();
276
22
    InterruptCallback::check();
277
22
}
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm7ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm8ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm9ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm10ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm11ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm12ELm8ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm13ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm14ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm15ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
Unexecuted instantiation: simdlib_based.cpp:_ZN5faiss12_GLOBAL__N_127exhaustive_L2sqr_fused_cmaxILm16ELm6ELm1EEEvPKfS3_mmRNS_22Top1BlockResultHandlerINS_4CMaxIflEELb0EEES3_
278
279
} // namespace
280
281
bool exhaustive_L2sqr_fused_cmax_simdlib(
282
        const float* x,
283
        const float* y,
284
        size_t d,
285
        size_t nx,
286
        size_t ny,
287
        Top1BlockResultHandler<CMax<float, int64_t>>& res,
288
278
        const float* y_norms) {
289
    // Process only cases with certain dimensionalities.
290
    // An acceptable dimensionality value is limited by the number of
291
    // available registers.
292
293
278
#define DISPATCH(DIM, NX_POINTS_PER_LOOP, NY_POINTS_PER_LOOP)    \
294
278
    case DIM: {                                                  \
295
99
        exhaustive_L2sqr_fused_cmax<                             \
296
99
                DIM,                                             \
297
99
                NX_POINTS_PER_LOOP,                              \
298
99
                NY_POINTS_PER_LOOP>(x, y, nx, ny, res, y_norms); \
299
99
        return true;                                             \
300
99
    }
301
302
    // faiss/benchs/bench_quantizer.py was used for benchmarking
303
    // and tuning 2nd and 3rd parameters values.
304
    // Basically, the larger the values for 2nd and 3rd parameters are,
305
    // the faster the execution is, but the more SIMD registers are needed.
306
    // This can be compensated with L1 cache, this is why this
307
    // code might operate with more registers than available
308
    // because of concurrent ports operations for ALU and LOAD/STORE.
309
310
278
#if defined(__AVX2__)
311
    // It was possible to tweak these parameters on x64 machine.
312
278
    switch (d) {
313
0
        DISPATCH(1, 6, 1)
314
0
        DISPATCH(2, 6, 1)
315
0
        DISPATCH(3, 6, 1)
316
77
        DISPATCH(4, 8, 1)
317
0
        DISPATCH(5, 8, 1)
318
22
        DISPATCH(6, 8, 1)
319
0
        DISPATCH(7, 8, 1)
320
0
        DISPATCH(8, 8, 1)
321
0
        DISPATCH(9, 8, 1)
322
0
        DISPATCH(10, 8, 1)
323
0
        DISPATCH(11, 8, 1)
324
0
        DISPATCH(12, 8, 1)
325
0
        DISPATCH(13, 6, 1)
326
0
        DISPATCH(14, 6, 1)
327
0
        DISPATCH(15, 6, 1)
328
278
        DISPATCH(16, 6, 1)
329
278
    }
330
#else
331
    // Please feel free to alter 2nd and 3rd parameters if you have access
332
    // to ARM-based machine so that you are able to benchmark this code.
333
    // Or to enable other dimensions.
334
    switch (d) {
335
        DISPATCH(1, 4, 2)
336
        DISPATCH(2, 2, 2)
337
        DISPATCH(3, 2, 2)
338
        DISPATCH(4, 2, 1)
339
        DISPATCH(5, 1, 1)
340
        DISPATCH(6, 1, 1)
341
        DISPATCH(7, 1, 1)
342
        DISPATCH(8, 1, 1)
343
    }
344
#endif
345
346
179
    return false;
347
278
#undef DISPATCH
348
278
}
349
350
} // namespace faiss
351
352
#endif