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.
- package/README.md +1 -1
- package/binding.gyp +101 -0
- package/c/CMakeLists.txt +27 -0
- package/c/README.md +34 -0
- package/c/lib.cpp +362 -0
- package/c/test.c +382 -0
- package/c/usearch.h +356 -0
- package/cmake/clipp.cmake +7 -0
- package/cmake/config.cmake.in +15 -0
- package/cmake/emscripten.cmake +8 -0
- package/cmake/jemalloc.cmake +62 -0
- package/cmake/pkg-config.pc.in +4 -0
- package/cmake/usearchConfigVersion.cmake.in +20 -0
- package/cpp/CMakeLists.txt +14 -0
- package/cpp/README.md +161 -0
- package/cpp/bench.cpp +616 -0
- package/cpp/test.cpp +324 -0
- package/fp16/CMakeLists.txt +176 -0
- package/fp16/LICENSE +11 -0
- package/fp16/README.md +20 -0
- package/fp16/bench/alt-element.cc +89 -0
- package/fp16/bench/from-alt-array.cc +175 -0
- package/fp16/bench/from-ieee-array.cc +399 -0
- package/fp16/bench/ieee-element.cc +272 -0
- package/fp16/bench/to-alt-array.cc +91 -0
- package/fp16/bench/to-ieee-array.cc +303 -0
- package/fp16/cmake/DownloadGoogleBenchmark.cmake +15 -0
- package/fp16/cmake/DownloadGoogleTest.cmake +15 -0
- package/fp16/cmake/DownloadPSimd.cmake +15 -0
- package/fp16/configure.py +65 -0
- package/fp16/confu.yaml +8 -0
- package/fp16/include/fp16/__init__.py +0 -0
- package/fp16/include/fp16/avx.py +50 -0
- package/fp16/include/fp16/avx2.py +53 -0
- package/fp16/include/fp16/bitcasts.h +92 -0
- package/fp16/include/fp16/fp16.h +451 -0
- package/fp16/include/fp16/psimd.h +131 -0
- package/fp16/include/fp16.h +11 -0
- package/fp16/jni/Android.mk +6 -0
- package/fp16/jni/Application.mk +4 -0
- package/fp16/test/alt-from-fp32-value.cc +498 -0
- package/fp16/test/alt-to-fp32-bits.cc +263 -0
- package/fp16/test/alt-to-fp32-psimd.cc +145 -0
- package/fp16/test/alt-to-fp32-value.cc +348 -0
- package/fp16/test/alt-to-fp32x2-psimd.cc +245 -0
- package/fp16/test/bitcasts.cc +56 -0
- package/fp16/test/ieee-from-fp32-value.cc +523 -0
- package/fp16/test/ieee-to-fp32-bits.cc +333 -0
- package/fp16/test/ieee-to-fp32-psimd.cc +312 -0
- package/fp16/test/ieee-to-fp32-value.cc +420 -0
- package/fp16/test/ieee-to-fp32x2-psimd.cc +541 -0
- package/fp16/test/peachpy/alt-xmm-to-fp32-xmm-avx.cc +96 -0
- package/fp16/test/peachpy/alt-xmm-to-fp32-ymm-avx2.cc +96 -0
- package/fp16/test/peachpy/stubs.py +38 -0
- package/fp16/test/tables.cc +530 -0
- package/fp16/test/tables.h +13 -0
- package/fp16/third-party/THHalf.h +92 -0
- package/fp16/third-party/eigen-half.h +170 -0
- package/fp16/third-party/float16-compressor.h +80 -0
- package/fp16/third-party/half.hpp +2916 -0
- package/fp16/third-party/npy-halffloat.h +328 -0
- package/include/usearch/index.hpp +3838 -0
- package/include/usearch/index_dense.hpp +2004 -0
- package/include/usearch/index_plugins.hpp +2255 -0
- package/javascript/dist-package-cjs.json +3 -0
- package/javascript/dist-package-esm.json +3 -0
- package/javascript/lib.cpp +350 -0
- package/javascript/node-gyp-build.d.ts +1 -0
- package/javascript/tsconfig-base.json +25 -0
- package/javascript/tsconfig-cjs.json +8 -0
- package/javascript/tsconfig-esm.json +8 -0
- package/javascript/usearch.test.js +84 -0
- package/javascript/usearch.ts +640 -0
- package/package.json +10 -3
- package/prebuilds/darwin-arm64+x64/usearch.node +0 -0
- package/prebuilds/linux-arm64/usearch.node +0 -0
- package/prebuilds/linux-x64/usearch.node +0 -0
- package/prebuilds/win32-ia32/usearch.node +0 -0
- package/prebuilds/win32-x64/usearch.node +0 -0
- package/simsimd/.releaserc +87 -0
- package/simsimd/CONTRIBUTING.md +114 -0
- package/simsimd/Cargo.lock +709 -0
- package/simsimd/Cargo.toml +44 -0
- package/simsimd/LICENSE +201 -0
- package/simsimd/README.md +708 -0
- package/simsimd/binding.gyp +36 -0
- package/simsimd/build.rs +51 -0
- package/simsimd/c/lib.c +110 -0
- package/simsimd/include/simsimd/binary.h +258 -0
- package/simsimd/include/simsimd/dot.h +1237 -0
- package/simsimd/include/simsimd/geospatial.h +37 -0
- package/simsimd/include/simsimd/probability.h +563 -0
- package/simsimd/include/simsimd/simsimd.h +1129 -0
- package/simsimd/include/simsimd/spatial.h +1019 -0
- package/simsimd/include/simsimd/types.h +309 -0
- package/simsimd/javascript/bench.js +127 -0
- package/simsimd/javascript/dist-package-cjs.json +3 -0
- package/simsimd/javascript/dist-package-esm.json +3 -0
- package/simsimd/javascript/fallback.ts +203 -0
- package/simsimd/javascript/lib.c +107 -0
- package/simsimd/javascript/node-gyp-build.d.ts +1 -0
- package/simsimd/javascript/simsimd.ts +135 -0
- package/simsimd/javascript/test.mjs +179 -0
- package/simsimd/javascript/tsconfig-base.json +37 -0
- package/simsimd/javascript/tsconfig-cjs.json +8 -0
- package/simsimd/javascript/tsconfig-esm.json +8 -0
- package/simsimd/package-lock.json +1709 -0
- package/simsimd/package.json +61 -0
- package/simsimd/rust/benches/cosine.rs +27 -0
- package/simsimd/rust/benches/native.rs +30 -0
- package/simsimd/rust/benches/sqeuclidean.rs +27 -0
- 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
|
+
)
|