usearch 2.10.3 → 2.10.5

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.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +101 -0
  3. package/c/CMakeLists.txt +27 -0
  4. package/c/README.md +34 -0
  5. package/c/lib.cpp +362 -0
  6. package/c/test.c +382 -0
  7. package/c/usearch.h +356 -0
  8. package/cmake/clipp.cmake +7 -0
  9. package/cmake/config.cmake.in +15 -0
  10. package/cmake/emscripten.cmake +8 -0
  11. package/cmake/jemalloc.cmake +62 -0
  12. package/cmake/pkg-config.pc.in +4 -0
  13. package/cmake/usearchConfigVersion.cmake.in +20 -0
  14. package/cpp/CMakeLists.txt +14 -0
  15. package/cpp/README.md +161 -0
  16. package/cpp/bench.cpp +616 -0
  17. package/cpp/test.cpp +324 -0
  18. package/fp16/CMakeLists.txt +176 -0
  19. package/fp16/LICENSE +11 -0
  20. package/fp16/README.md +20 -0
  21. package/fp16/bench/alt-element.cc +89 -0
  22. package/fp16/bench/from-alt-array.cc +175 -0
  23. package/fp16/bench/from-ieee-array.cc +399 -0
  24. package/fp16/bench/ieee-element.cc +272 -0
  25. package/fp16/bench/to-alt-array.cc +91 -0
  26. package/fp16/bench/to-ieee-array.cc +303 -0
  27. package/fp16/cmake/DownloadGoogleBenchmark.cmake +15 -0
  28. package/fp16/cmake/DownloadGoogleTest.cmake +15 -0
  29. package/fp16/cmake/DownloadPSimd.cmake +15 -0
  30. package/fp16/configure.py +65 -0
  31. package/fp16/confu.yaml +8 -0
  32. package/fp16/include/fp16/__init__.py +0 -0
  33. package/fp16/include/fp16/avx.py +50 -0
  34. package/fp16/include/fp16/avx2.py +53 -0
  35. package/fp16/include/fp16/bitcasts.h +92 -0
  36. package/fp16/include/fp16/fp16.h +451 -0
  37. package/fp16/include/fp16/psimd.h +131 -0
  38. package/fp16/include/fp16.h +11 -0
  39. package/fp16/jni/Android.mk +6 -0
  40. package/fp16/jni/Application.mk +4 -0
  41. package/fp16/test/alt-from-fp32-value.cc +498 -0
  42. package/fp16/test/alt-to-fp32-bits.cc +263 -0
  43. package/fp16/test/alt-to-fp32-psimd.cc +145 -0
  44. package/fp16/test/alt-to-fp32-value.cc +348 -0
  45. package/fp16/test/alt-to-fp32x2-psimd.cc +245 -0
  46. package/fp16/test/bitcasts.cc +56 -0
  47. package/fp16/test/ieee-from-fp32-value.cc +523 -0
  48. package/fp16/test/ieee-to-fp32-bits.cc +333 -0
  49. package/fp16/test/ieee-to-fp32-psimd.cc +312 -0
  50. package/fp16/test/ieee-to-fp32-value.cc +420 -0
  51. package/fp16/test/ieee-to-fp32x2-psimd.cc +541 -0
  52. package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +96 -0
  53. package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +96 -0
  54. package/fp16/test/peachpy/stubs.py +38 -0
  55. package/fp16/test/tables.cc +530 -0
  56. package/fp16/test/tables.h +13 -0
  57. package/fp16/third-party/THHalf.h +92 -0
  58. package/fp16/third-party/eigen-half.h +170 -0
  59. package/fp16/third-party/float16-compressor.h +80 -0
  60. package/fp16/third-party/half.hpp +2916 -0
  61. package/fp16/third-party/npy-halffloat.h +328 -0
  62. package/include/usearch/index.hpp +3838 -0
  63. package/include/usearch/index_dense.hpp +2004 -0
  64. package/include/usearch/index_plugins.hpp +2255 -0
  65. package/javascript/dist-package-cjs.json +3 -0
  66. package/javascript/dist-package-esm.json +3 -0
  67. package/javascript/lib.cpp +350 -0
  68. package/javascript/node-gyp-build.d.ts +1 -0
  69. package/javascript/tsconfig-base.json +25 -0
  70. package/javascript/tsconfig-cjs.json +8 -0
  71. package/javascript/tsconfig-esm.json +8 -0
  72. package/javascript/usearch.test.js +84 -0
  73. package/javascript/usearch.ts +640 -0
  74. package/package.json +10 -3
  75. package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
  76. package/prebuilds/linux-arm64/usearch.node +0 -0
  77. package/prebuilds/linux-x64/usearch.node +0 -0
  78. package/prebuilds/win32-ia32/usearch.node +0 -0
  79. package/prebuilds/win32-x64/usearch.node +0 -0
  80. package/simsimd/.releaserc +87 -0
  81. package/simsimd/CONTRIBUTING.md +114 -0
  82. package/simsimd/Cargo.lock +709 -0
  83. package/simsimd/Cargo.toml +44 -0
  84. package/simsimd/LICENSE +201 -0
  85. package/simsimd/README.md +708 -0
  86. package/simsimd/binding.gyp +36 -0
  87. package/simsimd/build.rs +51 -0
  88. package/simsimd/c/lib.c +110 -0
  89. package/simsimd/include/simsimd/binary.h +258 -0
  90. package/simsimd/include/simsimd/dot.h +1237 -0
  91. package/simsimd/include/simsimd/geospatial.h +37 -0
  92. package/simsimd/include/simsimd/probability.h +563 -0
  93. package/simsimd/include/simsimd/simsimd.h +1129 -0
  94. package/simsimd/include/simsimd/spatial.h +1019 -0
  95. package/simsimd/include/simsimd/types.h +309 -0
  96. package/simsimd/javascript/bench.js +127 -0
  97. package/simsimd/javascript/dist-package-cjs.json +3 -0
  98. package/simsimd/javascript/dist-package-esm.json +3 -0
  99. package/simsimd/javascript/fallback.ts +203 -0
  100. package/simsimd/javascript/lib.c +107 -0
  101. package/simsimd/javascript/node-gyp-build.d.ts +1 -0
  102. package/simsimd/javascript/simsimd.ts +135 -0
  103. package/simsimd/javascript/test.mjs +179 -0
  104. package/simsimd/javascript/tsconfig-base.json +37 -0
  105. package/simsimd/javascript/tsconfig-cjs.json +8 -0
  106. package/simsimd/javascript/tsconfig-esm.json +8 -0
  107. package/simsimd/package-lock.json +1709 -0
  108. package/simsimd/package.json +61 -0
  109. package/simsimd/rust/benches/cosine.rs +27 -0
  110. package/simsimd/rust/benches/native.rs +30 -0
  111. package/simsimd/rust/benches/sqeuclidean.rs +27 -0
  112. package/simsimd/rust/lib.rs +778 -0
@@ -0,0 +1,272 @@
1
+ #include <benchmark/benchmark.h>
2
+
3
+ #include <fp16.h>
4
+ #ifndef EMSCRIPTEN
5
+ #include <fp16/psimd.h>
6
+ #endif
7
+
8
+ #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
9
+ #include <immintrin.h>
10
+ #endif
11
+
12
+ #ifdef FP16_COMPARATIVE_BENCHMARKS
13
+ #include <third-party/THHalf.h>
14
+ #include <third-party/npy-halffloat.h>
15
+ #include <third-party/eigen-half.h>
16
+ #include <third-party/float16-compressor.h>
17
+ #include <third-party/half.hpp>
18
+ #endif
19
+
20
+ static inline uint16_t next_xorshift16(uint16_t x) {
21
+ x ^= x >> 8;
22
+ x ^= x << 9;
23
+ x ^= x >> 5;
24
+ return x;
25
+ }
26
+
27
+ static inline uint32_t next_xorshift32(uint32_t x) {
28
+ x ^= x >> 13;
29
+ x ^= x << 17;
30
+ x ^= x >> 5;
31
+ return x;
32
+ }
33
+ #ifndef EMSCRIPTEN
34
+ PSIMD_INTRINSIC psimd_u16 next_xorshift16_psimd(psimd_u16 x) {
35
+ x ^= x >> psimd_splat_u16(8);
36
+ x ^= x << psimd_splat_u16(9);
37
+ x ^= x >> psimd_splat_u16(5);
38
+ return x;
39
+ }
40
+ #endif
41
+
42
+
43
+ /* Conversion from IEEE FP16 to IEEE FP32 */
44
+
45
+ static void fp16_ieee_to_fp32_bits(benchmark::State& state) {
46
+ uint16_t fp16 = UINT16_C(0x7C00);
47
+ while (state.KeepRunning()) {
48
+ const uint32_t fp32 = fp16_ieee_to_fp32_bits(fp16);
49
+
50
+ fp16 = next_xorshift16(fp16);
51
+ benchmark::DoNotOptimize(fp32);
52
+ }
53
+ }
54
+ BENCHMARK(fp16_ieee_to_fp32_bits);
55
+
56
+ static void fp16_ieee_to_fp32_value(benchmark::State& state) {
57
+ uint16_t fp16 = UINT16_C(0x7C00);
58
+ while (state.KeepRunning()) {
59
+ const float fp32 = fp16_ieee_to_fp32_value(fp16);
60
+
61
+ fp16 = next_xorshift16(fp16);
62
+ benchmark::DoNotOptimize(fp32);
63
+ }
64
+ }
65
+ BENCHMARK(fp16_ieee_to_fp32_value);
66
+
67
+ #ifndef EMSCRIPTEN
68
+ static void fp16_ieee_to_fp32_psimd(benchmark::State& state) {
69
+ psimd_u16 fp16 = (psimd_u16) { 0x7C00, 0x7C01, 0x7C02, 0x7C03 };
70
+ while (state.KeepRunning()) {
71
+ const psimd_f32 fp32 = fp16_ieee_to_fp32_psimd(fp16);
72
+
73
+ fp16 = next_xorshift16_psimd(fp16);
74
+ benchmark::DoNotOptimize(fp32);
75
+ }
76
+ }
77
+ BENCHMARK(fp16_ieee_to_fp32_psimd);
78
+
79
+ static void fp16_ieee_to_fp32x2_psimd(benchmark::State& state) {
80
+ psimd_u16 fp16 =
81
+ (psimd_u16) { 0x7C00, 0x7C01, 0x7C02, 0x7C03, 0x7C04, 0x7C05, 0x7C06, 0x7C07 };
82
+ while (state.KeepRunning()) {
83
+ const psimd_f32x2 fp32 = fp16_ieee_to_fp32x2_psimd(fp16);
84
+
85
+ fp16 = next_xorshift16_psimd(fp16);
86
+ benchmark::DoNotOptimize(fp32);
87
+ }
88
+ }
89
+ BENCHMARK(fp16_ieee_to_fp32x2_psimd);
90
+ #endif
91
+
92
+ #ifdef FP16_COMPARATIVE_BENCHMARKS
93
+ static void TH_halfbits2float(benchmark::State& state) {
94
+ uint16_t fp16 = UINT16_C(0x7C00);
95
+ while (state.KeepRunning()) {
96
+ float fp32;
97
+ TH_halfbits2float(&fp16, &fp32);
98
+
99
+ fp16 = next_xorshift16(fp16);
100
+ benchmark::DoNotOptimize(fp32);
101
+ }
102
+ }
103
+ BENCHMARK(TH_halfbits2float);
104
+
105
+ static void npy_halfbits_to_floatbits(benchmark::State& state) {
106
+ uint16_t fp16 = UINT16_C(0x7C00);
107
+ while (state.KeepRunning()) {
108
+ const uint32_t fp32 = npy_halfbits_to_floatbits(fp16);
109
+
110
+ fp16 = next_xorshift16(fp16);
111
+ benchmark::DoNotOptimize(fp32);
112
+ }
113
+ }
114
+ BENCHMARK(npy_halfbits_to_floatbits);
115
+
116
+ static void Eigen_half_to_float(benchmark::State& state) {
117
+ uint16_t fp16 = UINT16_C(0x7C00);
118
+ while (state.KeepRunning()) {
119
+ const float fp32 =
120
+ Eigen::half_impl::half_to_float(
121
+ Eigen::half_impl::raw_uint16_to_half(fp16));
122
+
123
+ fp16 = next_xorshift16(fp16);
124
+ benchmark::DoNotOptimize(fp32);
125
+ }
126
+ }
127
+ BENCHMARK(Eigen_half_to_float);
128
+
129
+ static void Float16Compressor_decompress(benchmark::State& state) {
130
+ uint16_t fp16 = UINT16_C(0x7C00);
131
+ while (state.KeepRunning()) {
132
+ const float fp32 = Float16Compressor::decompress(fp16);
133
+
134
+ fp16 = next_xorshift16(fp16);
135
+ benchmark::DoNotOptimize(fp32);
136
+ }
137
+ }
138
+ BENCHMARK(Float16Compressor_decompress);
139
+
140
+ static void half_float_detail_half2float_table(benchmark::State& state) {
141
+ uint16_t fp16 = UINT16_C(0x7C00);
142
+ while (state.KeepRunning()) {
143
+ const float fp32 =
144
+ half_float::detail::half2float_impl(fp16,
145
+ half_float::detail::true_type());
146
+
147
+ fp16 = next_xorshift16(fp16);
148
+ benchmark::DoNotOptimize(fp32);
149
+ }
150
+ }
151
+ BENCHMARK(half_float_detail_half2float_table);
152
+
153
+ static void half_float_detail_half2float_branch(benchmark::State& state) {
154
+ uint16_t fp16 = UINT16_C(0x7C00);
155
+ while (state.KeepRunning()) {
156
+ const float fp32 =
157
+ half_float::detail::half2float_impl(fp16,
158
+ half_float::detail::false_type());
159
+
160
+ fp16 = next_xorshift16(fp16);
161
+ benchmark::DoNotOptimize(fp32);
162
+ }
163
+ }
164
+ BENCHMARK(half_float_detail_half2float_branch);
165
+ #endif
166
+
167
+ /* Conversion from IEEE FP32 to IEEE FP16 */
168
+
169
+ static void fp16_ieee_from_fp32_value(benchmark::State& state) {
170
+ uint32_t fp32 = UINT32_C(0x7F800000);
171
+ while (state.KeepRunning()) {
172
+ const uint16_t fp16 = fp16_ieee_from_fp32_value(fp32_from_bits(fp32));
173
+
174
+ fp32 = next_xorshift32(fp32);
175
+ benchmark::DoNotOptimize(fp16);
176
+ }
177
+ }
178
+ BENCHMARK(fp16_ieee_from_fp32_value);
179
+
180
+ #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
181
+ static void fp16_ieee_from_fp32_hardware(benchmark::State& state) {
182
+ uint32_t fp32 = UINT32_C(0x7F800000);
183
+ while (state.KeepRunning()) {
184
+ const uint16_t fp16 = static_cast<uint16_t>(
185
+ _mm_cvtsi128_si32(_mm_cvtps_ph(_mm_set_ss(fp32), _MM_FROUND_CUR_DIRECTION)));
186
+
187
+ fp32 = next_xorshift32(fp32);
188
+ benchmark::DoNotOptimize(fp16);
189
+ }
190
+ }
191
+ BENCHMARK(fp16_ieee_from_fp32_hardware);
192
+ #endif
193
+
194
+ #ifdef FP16_COMPARATIVE_BENCHMARKS
195
+ static void TH_float2halfbits(benchmark::State& state) {
196
+ uint32_t fp32 = UINT32_C(0x7F800000);
197
+ while (state.KeepRunning()) {
198
+ uint16_t fp16;
199
+ float fp32_value = fp32_from_bits(fp32);
200
+ TH_float2halfbits(&fp32_value, &fp16);
201
+
202
+ fp32 = next_xorshift32(fp32);
203
+ benchmark::DoNotOptimize(fp16);
204
+ }
205
+ }
206
+ BENCHMARK(TH_float2halfbits);
207
+
208
+ static void npy_floatbits_to_halfbits(benchmark::State& state) {
209
+ uint32_t fp32 = UINT32_C(0x7F800000);
210
+ while (state.KeepRunning()) {
211
+ const uint16_t fp16 = npy_floatbits_to_halfbits(fp32);
212
+
213
+ fp32 = next_xorshift32(fp32);
214
+ benchmark::DoNotOptimize(fp16);
215
+ }
216
+ }
217
+ BENCHMARK(npy_floatbits_to_halfbits);
218
+
219
+ static void Eigen_float_to_half_rtne(benchmark::State& state) {
220
+ uint32_t fp32 = UINT32_C(0x7F800000);
221
+ while (state.KeepRunning()) {
222
+ const Eigen::half_impl::__half fp16 =
223
+ Eigen::half_impl::float_to_half_rtne(
224
+ fp32_from_bits(fp32));
225
+
226
+ fp32 = next_xorshift32(fp32);
227
+ benchmark::DoNotOptimize(fp16);
228
+ }
229
+ }
230
+ BENCHMARK(Eigen_float_to_half_rtne);
231
+
232
+ static void Float16Compressor_compress(benchmark::State& state) {
233
+ uint32_t fp32 = UINT32_C(0x7F800000);
234
+ while (state.KeepRunning()) {
235
+ const uint16_t fp16 = Float16Compressor::compress(fp32_from_bits(fp32));
236
+
237
+ fp32 = next_xorshift32(fp32);
238
+ benchmark::DoNotOptimize(fp16);
239
+ }
240
+ }
241
+ BENCHMARK(Float16Compressor_compress);
242
+
243
+ static void half_float_detail_float2half_table(benchmark::State& state) {
244
+ uint32_t fp32 = UINT32_C(0x7F800000);
245
+ while (state.KeepRunning()) {
246
+ const uint16_t fp16 =
247
+ half_float::detail::float2half_impl<std::round_to_nearest>(
248
+ fp32_from_bits(fp32),
249
+ half_float::detail::true_type());
250
+
251
+ fp32 = next_xorshift32(fp32);
252
+ benchmark::DoNotOptimize(fp16);
253
+ }
254
+ }
255
+ BENCHMARK(half_float_detail_float2half_table);
256
+
257
+ static void half_float_detail_float2half_branch(benchmark::State& state) {
258
+ uint32_t fp32 = UINT32_C(0x7F800000);
259
+ while (state.KeepRunning()) {
260
+ const uint16_t fp16 =
261
+ half_float::detail::float2half_impl<std::round_to_nearest>(
262
+ fp32_from_bits(fp32),
263
+ half_float::detail::false_type());
264
+
265
+ fp32 = next_xorshift32(fp32);
266
+ benchmark::DoNotOptimize(fp16);
267
+ }
268
+ }
269
+ BENCHMARK(half_float_detail_float2half_branch);
270
+ #endif
271
+
272
+ BENCHMARK_MAIN();
@@ -0,0 +1,91 @@
1
+ #include <benchmark/benchmark.h>
2
+
3
+ #include <fp16.h>
4
+ #ifndef EMSCRIPTEN
5
+ #include <fp16/psimd.h>
6
+ #endif
7
+
8
+ #include <vector>
9
+ #include <random>
10
+ #include <chrono>
11
+ #include <functional>
12
+ #include <algorithm>
13
+
14
+ #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
15
+ #include <immintrin.h>
16
+ #endif
17
+
18
+ #if defined(__ARM_NEON__) || defined(__aarch64__)
19
+ #include <arm_neon.h>
20
+ #endif
21
+
22
+
23
+ static void fp16_alt_from_fp32_value(benchmark::State& state) {
24
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
25
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
26
+
27
+ std::vector<float> fp32(state.range(0));
28
+ std::vector<uint16_t> fp16(state.range(0));
29
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
30
+
31
+ while (state.KeepRunning()) {
32
+ float* input = fp32.data();
33
+ benchmark::DoNotOptimize(input);
34
+
35
+ uint16_t* output = fp16.data();
36
+ const size_t n = state.range(0);
37
+ for (size_t i = 0; i < n; i++) {
38
+ output[i] = fp16_alt_from_fp32_value(input[i]);
39
+ }
40
+
41
+ benchmark::DoNotOptimize(output);
42
+ }
43
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
44
+ }
45
+ BENCHMARK(fp16_alt_from_fp32_value)->RangeMultiplier(2)->Range(1<<10, 64<<20);
46
+
47
+ #if defined(__ARM_NEON_FP) && (__ARM_NEON_FP & 0x2) || defined(__aarch64__)
48
+ static void hardware_vcvt_f16_f32(benchmark::State& state) {
49
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
50
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
51
+
52
+ std::vector<float> fp32(state.range(0));
53
+ std::vector<uint16_t> fp16(state.range(0));
54
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
55
+
56
+ while (state.KeepRunning()) {
57
+ float* input = fp32.data();
58
+ benchmark::DoNotOptimize(input);
59
+
60
+ uint16_t* output = fp16.data();
61
+ const size_t n = state.range(0);
62
+ #if defined(__aarch64__)
63
+ const unsigned int fpcr = __builtin_aarch64_get_fpcr();
64
+ /* Disable flush-to-zero (bit 24) and enable Alternative FP16 format (bit 26) */
65
+ __builtin_aarch64_set_fpcr((fpcr & 0xFEFFFFFFu) | 0x08000000u);
66
+ #else
67
+ unsigned int fpscr;
68
+ __asm__ __volatile__ ("VMRS %[fpscr], fpscr" : [fpscr] "=r" (fpscr));
69
+ /* Disable flush-to-zero (bit 24) and enable Alternative FP16 format (bit 26) */
70
+ __asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :
71
+ : [fpscr] "r" ((fpscr & 0xFEFFFFFFu) | 0x08000000u));
72
+ #endif
73
+ for (size_t i = 0; i < n; i += 4) {
74
+ vst1_u16(&output[i],
75
+ (uint16x4_t) vcvt_f16_f32(
76
+ vld1q_f32(&input[i])));
77
+ }
78
+ #if defined(__aarch64__)
79
+ __builtin_aarch64_set_fpcr(fpcr);
80
+ #else
81
+ __asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :: [fpscr] "r" (fpscr));
82
+ #endif
83
+
84
+ benchmark::DoNotOptimize(output);
85
+ }
86
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
87
+ }
88
+ BENCHMARK(hardware_vcvt_f16_f32)->RangeMultiplier(2)->Range(1<<10, 64<<20);
89
+ #endif
90
+
91
+ BENCHMARK_MAIN();
@@ -0,0 +1,303 @@
1
+ #include <benchmark/benchmark.h>
2
+
3
+ #include <fp16.h>
4
+ #ifndef EMSCRIPTEN
5
+ #include <fp16/psimd.h>
6
+ #endif
7
+
8
+ #include <vector>
9
+ #include <random>
10
+ #include <chrono>
11
+ #include <functional>
12
+ #include <algorithm>
13
+
14
+ #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
15
+ #include <immintrin.h>
16
+ #endif
17
+
18
+ #if defined(__ARM_NEON__) || defined(__aarch64__)
19
+ #include <arm_neon.h>
20
+ #endif
21
+
22
+ #ifdef FP16_COMPARATIVE_BENCHMARKS
23
+ #include <third-party/THHalf.h>
24
+ #include <third-party/npy-halffloat.h>
25
+ #include <third-party/eigen-half.h>
26
+ #include <third-party/float16-compressor.h>
27
+ #include <third-party/half.hpp>
28
+ #endif
29
+
30
+
31
+ static void fp16_ieee_from_fp32_value(benchmark::State& state) {
32
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
33
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
34
+
35
+ std::vector<float> fp32(state.range(0));
36
+ std::vector<uint16_t> fp16(state.range(0));
37
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
38
+
39
+ while (state.KeepRunning()) {
40
+ float* input = fp32.data();
41
+ benchmark::DoNotOptimize(input);
42
+
43
+ uint16_t* output = fp16.data();
44
+ const size_t n = state.range(0);
45
+ for (size_t i = 0; i < n; i++) {
46
+ output[i] = fp16_ieee_from_fp32_value(input[i]);
47
+ }
48
+
49
+ benchmark::DoNotOptimize(output);
50
+ }
51
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
52
+ }
53
+ BENCHMARK(fp16_ieee_from_fp32_value)->RangeMultiplier(2)->Range(1<<10, 64<<20);
54
+
55
+ #if (defined(__i386__) || defined(__x86_64__)) && defined(__F16C__)
56
+ static void hardware_mm_cvtps_ph(benchmark::State& state) {
57
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
58
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
59
+
60
+ std::vector<float> fp32(state.range(0));
61
+ std::vector<uint16_t> fp16(state.range(0));
62
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
63
+
64
+ while (state.KeepRunning()) {
65
+ float* input = fp32.data();
66
+ benchmark::DoNotOptimize(input);
67
+
68
+ uint16_t* output = fp16.data();
69
+ const size_t n = state.range(0);
70
+ for (size_t i = 0; i < n; i += 4) {
71
+ _mm_storel_epi64(
72
+ static_cast<__m128i*>(static_cast<void*>(&output[i])),
73
+ _mm_cvtps_ph(_mm_loadu_ps(&input[i]), _MM_FROUND_CUR_DIRECTION));
74
+ }
75
+
76
+ benchmark::DoNotOptimize(output);
77
+ }
78
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
79
+ }
80
+ BENCHMARK(hardware_mm_cvtps_ph)->RangeMultiplier(2)->Range(1<<10, 64<<20);
81
+
82
+ static void hardware_mm256_cvtps_ph(benchmark::State& state) {
83
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
84
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
85
+
86
+ std::vector<float> fp32(state.range(0));
87
+ std::vector<uint16_t> fp16(state.range(0));
88
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
89
+
90
+ while (state.KeepRunning()) {
91
+ float* input = fp32.data();
92
+ benchmark::DoNotOptimize(input);
93
+
94
+ uint16_t* output = fp16.data();
95
+ const size_t n = state.range(0);
96
+ for (size_t i = 0; i < n; i += 8) {
97
+ _mm_storeu_si128(
98
+ static_cast<__m128i*>(static_cast<void*>(&output[i])),
99
+ _mm256_cvtps_ph(_mm256_loadu_ps(&input[i]), _MM_FROUND_CUR_DIRECTION));
100
+ }
101
+
102
+ benchmark::DoNotOptimize(output);
103
+ }
104
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
105
+ }
106
+ BENCHMARK(hardware_mm256_cvtps_ph)->RangeMultiplier(2)->Range(1<<10, 64<<20);
107
+ #endif
108
+
109
+ #if defined(__ARM_NEON_FP) && (__ARM_NEON_FP & 0x2) || defined(__aarch64__)
110
+ static void hardware_vcvt_f16_f32(benchmark::State& state) {
111
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
112
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
113
+
114
+ std::vector<float> fp32(state.range(0));
115
+ std::vector<uint16_t> fp16(state.range(0));
116
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
117
+
118
+ while (state.KeepRunning()) {
119
+ float* input = fp32.data();
120
+ benchmark::DoNotOptimize(input);
121
+
122
+ uint16_t* output = fp16.data();
123
+ const size_t n = state.range(0);
124
+ #if defined(__aarch64__)
125
+ const unsigned int fpcr = __builtin_aarch64_get_fpcr();
126
+ /* Disable flush-to-zero (bit 24) and Alternative FP16 format (bit 26) */
127
+ __builtin_aarch64_set_fpcr(fpcr & 0xF6FFFFFFu);
128
+ #else
129
+ unsigned int fpscr;
130
+ __asm__ __volatile__ ("VMRS %[fpscr], fpscr" : [fpscr] "=r" (fpscr));
131
+ /* Disable flush-to-zero (bit 24) and Alternative FP16 format (bit 26) */
132
+ __asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :
133
+ : [fpscr] "r" (fpscr & 0xF6FFFFFFu));
134
+ #endif
135
+ for (size_t i = 0; i < n; i += 4) {
136
+ vst1_u16(&output[i],
137
+ (uint16x4_t) vcvt_f16_f32(
138
+ vld1q_f32(&input[i])));
139
+ }
140
+ #if defined(__aarch64__)
141
+ __builtin_aarch64_set_fpcr(fpcr);
142
+ #else
143
+ __asm__ __volatile__ ("VMSR fpscr, %[fpscr]" :: [fpscr] "r" (fpscr));
144
+ #endif
145
+
146
+ benchmark::DoNotOptimize(output);
147
+ }
148
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
149
+ }
150
+ BENCHMARK(hardware_vcvt_f16_f32)->RangeMultiplier(2)->Range(1<<10, 64<<20);
151
+ #endif
152
+
153
+ #ifdef FP16_COMPARATIVE_BENCHMARKS
154
+ static void TH_float2halfbits(benchmark::State& state) {
155
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
156
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
157
+
158
+ std::vector<float> fp32(state.range(0));
159
+ std::vector<uint16_t> fp16(state.range(0));
160
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
161
+
162
+ while (state.KeepRunning()) {
163
+ float* input = fp32.data();
164
+ benchmark::DoNotOptimize(input);
165
+
166
+ uint16_t* output = fp16.data();
167
+ const size_t n = state.range(0);
168
+ for (size_t i = 0; i < n; i++) {
169
+ TH_float2halfbits(&input[i], &output[i]);
170
+ }
171
+
172
+ benchmark::DoNotOptimize(output);
173
+ }
174
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
175
+ }
176
+ BENCHMARK(TH_float2halfbits)->RangeMultiplier(2)->Range(1<<10, 64<<20);
177
+
178
+ static void npy_floatbits_to_halfbits(benchmark::State& state) {
179
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
180
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
181
+
182
+ std::vector<float> fp32(state.range(0));
183
+ std::vector<uint16_t> fp16(state.range(0));
184
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
185
+
186
+ while (state.KeepRunning()) {
187
+ float* input = fp32.data();
188
+ benchmark::DoNotOptimize(input);
189
+
190
+ uint16_t* output = fp16.data();
191
+ const size_t n = state.range(0);
192
+ for (size_t i = 0; i < n; i++) {
193
+ output[i] = npy_floatbits_to_halfbits(fp32_to_bits(input[i]));
194
+ }
195
+
196
+ benchmark::DoNotOptimize(output);
197
+ }
198
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
199
+ }
200
+ BENCHMARK(npy_floatbits_to_halfbits)->RangeMultiplier(2)->Range(1<<10, 64<<20);
201
+
202
+ static void Eigen_float_to_half_rtne(benchmark::State& state) {
203
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
204
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
205
+
206
+ std::vector<float> fp32(state.range(0));
207
+ std::vector<uint16_t> fp16(state.range(0));
208
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
209
+
210
+ while (state.KeepRunning()) {
211
+ float* input = fp32.data();
212
+ benchmark::DoNotOptimize(input);
213
+
214
+ uint16_t* output = fp16.data();
215
+ const size_t n = state.range(0);
216
+ for (size_t i = 0; i < n; i++) {
217
+ output[i] = Eigen::half_impl::float_to_half_rtne(input[i]).x;
218
+ }
219
+
220
+ benchmark::DoNotOptimize(output);
221
+ }
222
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
223
+ }
224
+ BENCHMARK(Eigen_float_to_half_rtne)->RangeMultiplier(2)->Range(1<<10, 64<<20);
225
+
226
+ static void Float16Compressor_compress(benchmark::State& state) {
227
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
228
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
229
+
230
+ std::vector<float> fp32(state.range(0));
231
+ std::vector<uint16_t> fp16(state.range(0));
232
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
233
+
234
+ while (state.KeepRunning()) {
235
+ float* input = fp32.data();
236
+ benchmark::DoNotOptimize(input);
237
+
238
+ uint16_t* output = fp16.data();
239
+ const size_t n = state.range(0);
240
+ for (size_t i = 0; i < n; i++) {
241
+ output[i] = Float16Compressor::compress(input[i]);
242
+ }
243
+
244
+ benchmark::DoNotOptimize(output);
245
+ }
246
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
247
+ }
248
+ BENCHMARK(Float16Compressor_compress)->RangeMultiplier(2)->Range(1<<10, 64<<20);
249
+
250
+ static void half_float_detail_float2half_table(benchmark::State& state) {
251
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
252
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
253
+
254
+ std::vector<float> fp32(state.range(0));
255
+ std::vector<uint16_t> fp16(state.range(0));
256
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
257
+
258
+ while (state.KeepRunning()) {
259
+ float* input = fp32.data();
260
+ benchmark::DoNotOptimize(input);
261
+
262
+ uint16_t* output = fp16.data();
263
+ const size_t n = state.range(0);
264
+ for (size_t i = 0; i < n; i++) {
265
+ output[i] =
266
+ half_float::detail::float2half_impl<std::round_to_nearest>(
267
+ input[i], half_float::detail::true_type());
268
+ }
269
+
270
+ benchmark::DoNotOptimize(output);
271
+ }
272
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
273
+ }
274
+ BENCHMARK(half_float_detail_float2half_table)->RangeMultiplier(2)->Range(1<<10, 64<<20);
275
+
276
+ static void half_float_detail_float2half_branch(benchmark::State& state) {
277
+ const uint_fast32_t seed = std::chrono::system_clock::now().time_since_epoch().count();
278
+ auto rng = std::bind(std::uniform_real_distribution<float>(-1.0f, 1.0f), std::mt19937(seed));
279
+
280
+ std::vector<float> fp32(state.range(0));
281
+ std::vector<uint16_t> fp16(state.range(0));
282
+ std::generate(fp32.begin(), fp32.end(), std::ref(rng));
283
+
284
+ while (state.KeepRunning()) {
285
+ float* input = fp32.data();
286
+ benchmark::DoNotOptimize(input);
287
+
288
+ uint16_t* output = fp16.data();
289
+ const size_t n = state.range(0);
290
+ for (size_t i = 0; i < n; i++) {
291
+ output[i] =
292
+ half_float::detail::float2half_impl<std::round_to_nearest>(
293
+ input[i], half_float::detail::false_type());
294
+ }
295
+
296
+ benchmark::DoNotOptimize(output);
297
+ }
298
+ state.SetItemsProcessed(int64_t(state.iterations()) * int64_t(state.range(0)));
299
+ }
300
+ BENCHMARK(half_float_detail_float2half_branch)->RangeMultiplier(2)->Range(1<<10, 64<<20);
301
+ #endif
302
+
303
+ BENCHMARK_MAIN();
@@ -0,0 +1,15 @@
1
+ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
2
+
3
+ PROJECT(googlebenchmark-download NONE)
4
+
5
+ INCLUDE(ExternalProject)
6
+ ExternalProject_Add(googlebenchmark
7
+ URL https://github.com/google/benchmark/archive/v1.2.0.zip
8
+ URL_HASH SHA256=cc463b28cb3701a35c0855fbcefb75b29068443f1952b64dd5f4f669272e95ea
9
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-source"
10
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googlebenchmark"
11
+ CONFIGURE_COMMAND ""
12
+ BUILD_COMMAND ""
13
+ INSTALL_COMMAND ""
14
+ TEST_COMMAND ""
15
+ )
@@ -0,0 +1,15 @@
1
+ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 FATAL_ERROR)
2
+
3
+ PROJECT(googletest-download NONE)
4
+
5
+ INCLUDE(ExternalProject)
6
+ ExternalProject_Add(googletest
7
+ URL https://github.com/google/googletest/archive/release-1.8.0.zip
8
+ URL_HASH SHA256=f3ed3b58511efd272eb074a3a6d6fb79d7c2e6a0e374323d1e6bcbcc1ef141bf
9
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-source"
10
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googletest"
11
+ CONFIGURE_COMMAND ""
12
+ BUILD_COMMAND ""
13
+ INSTALL_COMMAND ""
14
+ TEST_COMMAND ""
15
+ )