usearch 0.22.3 → 1.1.0
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/.github/workflows/prerelease.yml +3 -3
- package/.releaserc +10 -2
- package/.vscode/launch.json +10 -10
- package/.vscode/settings.json +9 -1
- package/.vscode/tasks.json +4 -4
- package/CMakeLists.txt +6 -1
- package/Cargo.toml +2 -2
- package/README.md +35 -41
- package/build.rs +2 -2
- package/c/CMakeLists.txt +48 -0
- package/c/README.md +34 -0
- package/c/lib.cpp +83 -72
- package/c/test.c +20 -20
- package/c/usearch.h +132 -32
- package/conanfile.py +1 -1
- package/cpp/CMakeLists.txt +3 -1
- package/cpp/README.md +16 -16
- package/cpp/bench.cpp +50 -126
- package/cpp/test.cpp +164 -80
- package/docs/benchmarks.md +26 -5
- package/docs/c/reference.rst +3 -3
- package/docs/compilation.md +31 -49
- package/docs/cpp/index.rst +1 -1
- package/docs/cpp/reference.rst +4 -4
- package/golang/lib.go +275 -141
- package/golang/lib_test.go +105 -0
- package/include/usearch/index.hpp +1681 -1656
- package/include/usearch/index_dense.hpp +1400 -0
- package/include/usearch/index_plugins.hpp +1263 -0
- package/java/README.md +1 -1
- package/java/cloud/unum/usearch/Index.java +10 -10
- package/java/cloud/unum/usearch/cloud_unum_usearch_Index.cpp +34 -37
- package/java/test/IndexTest.java +1 -1
- package/javascript/README.md +6 -6
- package/javascript/lib.cpp +156 -55
- package/javascript/test.js +26 -11
- package/javascript/usearch.d.ts +102 -0
- package/javascript/usearch.js +2 -118
- package/objc/USearchObjective.mm +57 -31
- package/objc/include/USearchObjective.h +32 -22
- package/package.json +5 -3
- package/python/README.md +23 -14
- package/python/lib.cpp +468 -444
- package/python/scripts/bench.ipynb +3 -2
- package/python/scripts/bench.py +4 -4
- package/python/scripts/index_faiss.py +5 -5
- package/python/scripts/join.py +4 -4
- package/python/scripts/test.py +152 -61
- package/python/scripts/test_jit.py +10 -12
- package/python/scripts/test_sparse.py +32 -0
- package/python/usearch/client.py +26 -28
- package/python/usearch/eval.py +73 -23
- package/python/usearch/index.py +520 -228
- package/python/usearch/io.py +57 -25
- package/python/usearch/numba.py +4 -4
- package/python/usearch/server.py +10 -10
- package/rust/lib.cpp +34 -30
- package/rust/lib.hpp +14 -12
- package/rust/lib.rs +8 -7
- package/setup.py +5 -2
- package/simsimd/.github/workflows/prerelease.yml +73 -0
- package/simsimd/.github/workflows/release.yml +110 -0
- package/simsimd/.github/workflows/update_version.sh +3 -0
- package/simsimd/.releaserc +77 -0
- package/simsimd/.vscode/launch.json +27 -1
- package/simsimd/.vscode/settings.json +22 -1
- package/simsimd/.vscode/tasks.json +6 -0
- package/simsimd/CMakeLists.txt +3 -2
- package/simsimd/README.md +82 -46
- package/simsimd/bench.cxx +63 -24
- package/simsimd/include/simsimd/simsimd.h +88 -66
- package/simsimd/include/simsimd/simsimd_chem.h +126 -0
- package/simsimd/package.json +8 -0
- package/simsimd/pyproject.toml +42 -0
- package/simsimd/python/python.c +81 -0
- package/simsimd/python/run.sh +1 -0
- package/simsimd/python/test.c +109 -0
- package/simsimd/python/test.py +23 -0
- package/simsimd/setup.py +44 -0
- package/swift/Index+Sugar.swift +75 -23
- package/swift/README.md +26 -2
- package/swift/Test.swift +19 -7
- package/swift/USearch.swift +2 -2
- package/tsconfig.json +8 -0
- package/wasm/CMakeLists.txt +1 -0
- package/wasmer.toml +1 -1
- package/wolfram/CMakeLists.txt +1 -0
- package/wolfram/lib.cpp +11 -13
- package/golang/usearch.h +0 -9
- package/golang/usearch_par_test.go +0 -40
- package/golang/usearch_test.go +0 -82
- package/include/usearch/index_punned_dense.hpp +0 -1001
- package/include/usearch/index_punned_helpers.hpp +0 -676
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"branches": [
|
|
3
|
+
"main"
|
|
4
|
+
],
|
|
5
|
+
"debug": true,
|
|
6
|
+
"ci": true,
|
|
7
|
+
"dryRun": false,
|
|
8
|
+
"plugins": [
|
|
9
|
+
[
|
|
10
|
+
"@semantic-release/commit-analyzer",
|
|
11
|
+
{
|
|
12
|
+
"preset": "eslint",
|
|
13
|
+
"releaseRules": [
|
|
14
|
+
{
|
|
15
|
+
"tag": "Add",
|
|
16
|
+
"release": "minor"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"tag": "Improve",
|
|
20
|
+
"release": "patch"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"tag": "Make",
|
|
24
|
+
"release": "patch"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"tag": "Refactor",
|
|
28
|
+
"release": false
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
"@semantic-release/release-notes-generator",
|
|
35
|
+
{
|
|
36
|
+
"preset": "eslint",
|
|
37
|
+
"releaseRules": [
|
|
38
|
+
{
|
|
39
|
+
"tag": "Add",
|
|
40
|
+
"release": "minor"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"tag": "Improve",
|
|
44
|
+
"release": "patch"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"tag": "Make",
|
|
48
|
+
"release": "patch"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"tag": "Refactor",
|
|
52
|
+
"release": false
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"@semantic-release/github",
|
|
58
|
+
[
|
|
59
|
+
"@semantic-release/exec",
|
|
60
|
+
{
|
|
61
|
+
"prepareCmd": "bash .github/workflows/update_version.sh '${nextRelease.version}'"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
"@semantic-release/git",
|
|
66
|
+
{
|
|
67
|
+
"assets": [
|
|
68
|
+
"VERSION",
|
|
69
|
+
"conanfile.py",
|
|
70
|
+
"package.json",
|
|
71
|
+
"Cargo.toml",
|
|
72
|
+
],
|
|
73
|
+
"message": "Build: Released ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
]
|
|
77
|
+
}
|
|
@@ -18,7 +18,33 @@
|
|
|
18
18
|
],
|
|
19
19
|
"stopAtEntry": false,
|
|
20
20
|
"preLaunchTask": "Build Benchmark: Debug",
|
|
21
|
-
"
|
|
21
|
+
"linux": {
|
|
22
|
+
"MIMode": "gdb",
|
|
23
|
+
},
|
|
24
|
+
"osx": {
|
|
25
|
+
"MIMode": "lldb"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "Debug Test",
|
|
30
|
+
"type": "cppdbg",
|
|
31
|
+
"request": "launch",
|
|
32
|
+
"program": "${workspaceFolder}/build/test",
|
|
33
|
+
"cwd": "${workspaceFolder}",
|
|
34
|
+
"environment": [
|
|
35
|
+
{
|
|
36
|
+
"name": "ASAN_OPTIONS",
|
|
37
|
+
"value": "detect_leaks=0:atexit=1:strict_init_order=1:strict_string_checks=1"
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"stopAtEntry": false,
|
|
41
|
+
"preLaunchTask": "Build Test: Debug",
|
|
42
|
+
"linux": {
|
|
43
|
+
"MIMode": "gdb"
|
|
44
|
+
},
|
|
45
|
+
"osx": {
|
|
46
|
+
"MIMode": "lldb"
|
|
47
|
+
}
|
|
22
48
|
}
|
|
23
49
|
]
|
|
24
50
|
}
|
|
@@ -64,7 +64,28 @@
|
|
|
64
64
|
"thread": "cpp",
|
|
65
65
|
"typeinfo": "cpp",
|
|
66
66
|
"complex": "cpp",
|
|
67
|
-
"immintrin.h": "c"
|
|
67
|
+
"immintrin.h": "c",
|
|
68
|
+
"__bit_reference": "cpp",
|
|
69
|
+
"__bits": "cpp",
|
|
70
|
+
"__config": "cpp",
|
|
71
|
+
"__debug": "cpp",
|
|
72
|
+
"__errc": "cpp",
|
|
73
|
+
"__hash_table": "cpp",
|
|
74
|
+
"__locale": "cpp",
|
|
75
|
+
"__mutex_base": "cpp",
|
|
76
|
+
"__node_handle": "cpp",
|
|
77
|
+
"__split_buffer": "cpp",
|
|
78
|
+
"__threading_support": "cpp",
|
|
79
|
+
"__tuple": "cpp",
|
|
80
|
+
"__verbose_abort": "cpp",
|
|
81
|
+
"charconv": "cpp",
|
|
82
|
+
"ios": "cpp",
|
|
83
|
+
"locale": "cpp",
|
|
84
|
+
"optional": "cpp",
|
|
85
|
+
"variant": "cpp",
|
|
86
|
+
"__nullptr": "cpp",
|
|
87
|
+
"unordered_set": "cpp",
|
|
88
|
+
"span": "cpp"
|
|
68
89
|
},
|
|
69
90
|
"cSpell.words": [
|
|
70
91
|
"dtype",
|
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
"args": [],
|
|
8
8
|
"type": "shell"
|
|
9
9
|
},
|
|
10
|
+
{
|
|
11
|
+
"label": "Build Test: Debug",
|
|
12
|
+
"command": "cmake -DCMAKE_BUILD_TYPE=Debug -B ./build && make test py_simsimd -C ./build",
|
|
13
|
+
"args": [],
|
|
14
|
+
"type": "shell"
|
|
15
|
+
},
|
|
10
16
|
{
|
|
11
17
|
"label": "Build Benchmark: Release",
|
|
12
18
|
"command": "cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -B ./build_release && make -j 2 -C ./build_release",
|
package/simsimd/CMakeLists.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
|
|
2
|
-
project(simsimd LANGUAGES CXX)
|
|
3
|
-
set(CMAKE_CXX_STANDARD
|
|
2
|
+
project(simsimd LANGUAGES CXX C)
|
|
3
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
4
4
|
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
|
5
5
|
set(CMAKE_CXX_EXTENSIONS NO)
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ option(SIMSIMD_BUILD_BENCHMARKS "Compile a micro-benchmark for current ISA" OFF)
|
|
|
9
9
|
|
|
10
10
|
# Get external content: Google Benchmark, Thrust
|
|
11
11
|
include(FetchContent)
|
|
12
|
+
include_directories(include/)
|
|
12
13
|
|
|
13
14
|
# Fetch GBenchmark and surpress internal tests.
|
|
14
15
|
# https://github.com/google/benchmark/blob/main/docs/user_guide.md#using-register-benchmark
|
package/simsimd/README.md
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
# SimSIMD
|
|
2
2
|
|
|
3
3
|
SIMD-accelerated similarity measures, metrics, distance functions for x86 and Arm.
|
|
4
|
-
Tuned for Machine Learning applications, mid-size vectors with 100-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
|
8
|
-
|
|
|
9
|
-
| `f32`
|
|
10
|
-
| `f32`
|
|
11
|
-
|
|
|
12
|
-
| `f16`
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
4
|
+
Tuned for Machine Learning applications, mid-size vectors with 100-1024 dimensions.
|
|
5
|
+
For Cosine (Angular) distance, the most common metric in AI, one can expect following performance.
|
|
6
|
+
|
|
7
|
+
| Method | Vectors | Any Length | Speed on 256b | Speed on 1024b |
|
|
8
|
+
| :----- | :------ | :--------- | ------------: | -------------: |
|
|
9
|
+
| Serial | `f32` | ✅ | 5 GB/s | 5 GB/s |
|
|
10
|
+
| SVE | `f32` | ✅ | 34 GB/s | 40 GB/s |
|
|
11
|
+
| SVE | `f16` | ✅ | 28 GB/s | 35 GB/s |
|
|
12
|
+
| NEON | `f16` | ❌ | 16 GB/s | 18 GB/s |
|
|
13
|
+
|
|
14
|
+
> The benchmarks were done on Arm-based "Graviton 3" CPUs powering AWS `c7g.metal` instances.
|
|
15
|
+
> We only use Arm NEON implementation with vectors lengths that are multiples of 128 bits, avoiding any additional head or tail `for` loops for misaligned data.
|
|
16
|
+
> By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
|
|
17
|
+
> Serial versions imply auto-vectorization pragmas.
|
|
16
18
|
|
|
17
19
|
Need something like this in your CMake-based project?
|
|
18
20
|
|
|
@@ -26,49 +28,76 @@ FetchContent_MakeAvailable(simsimd)
|
|
|
26
28
|
include_directories(${simsimd_SOURCE_DIR}/include)
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
By default, we use GCC12, `-O3`, `-march=native` for benchmarks.
|
|
32
|
-
Serial versions imply auto-vectorization pragmas.
|
|
31
|
+
Want to use in Python with [USearch](https://github.com/unum-cloud/usearch)?
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
```py
|
|
34
|
+
from usearch import Index, CompiledMetric, MetricKind, MetricSignature
|
|
35
|
+
from simsimd import to_int, cos_f32x4_neon
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
| Serial | `f32` x256 | ✅ | 5 GB/s |
|
|
42
|
-
| | | | |
|
|
43
|
-
| NEON | `f32` x16 | ❌ | 18 GB/s |
|
|
44
|
-
| NEON | `f32` x256 | ❌ | 29 GB/s |
|
|
45
|
-
| | | | |
|
|
46
|
-
| SVE | `f32` x16 | ✅ | 15 GB/s |
|
|
47
|
-
| SVE | `f32` x256 | ✅ | 39 GB/s |
|
|
48
|
-
|
|
49
|
-
We only use Arm NEON implementation with vectors lengths that are multiples of 128 bits, avoiding any additional head or tail `for` loops for misaligned data.
|
|
50
|
-
SVE looses to NEON on very short vectors, but outperforms on longer sequences.
|
|
51
|
-
|
|
52
|
-
---
|
|
37
|
+
metric = CompiledMetric(
|
|
38
|
+
pointer=to_int(cos_f32x4_neon),
|
|
39
|
+
kind=MetricKind.Cos,
|
|
40
|
+
signature=MetricSignature.ArrayArraySize,
|
|
41
|
+
)
|
|
53
42
|
|
|
54
|
-
|
|
43
|
+
index = Index(256, metric=metric)
|
|
44
|
+
```
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
## Available Metrics
|
|
47
|
+
|
|
48
|
+
In the C99 interface all function are prepended with `simsimd_` namespace prefix.
|
|
49
|
+
Signature defines the number of arguments:
|
|
50
|
+
|
|
51
|
+
- two pointers, and length,
|
|
52
|
+
- two pointers.
|
|
53
|
+
|
|
54
|
+
The latter is obviously intended for cases, where the number of dimensions is hard-coded.
|
|
55
|
+
Constraints define the limitations on the number of dimensions that an argument vector can have.
|
|
56
|
+
|
|
57
|
+
| Name | Signature | ISA Extesion | Constraints |
|
|
58
|
+
| :---------------------- | :-------: | :----------: | :------------: |
|
|
59
|
+
| `dot_f32_sve` | ✳️✳️📏 | Arm SVE | |
|
|
60
|
+
| `dot_f32x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
|
|
61
|
+
| `cos_f32_sve` | ✳️✳️📏 | Arm SVE | |
|
|
62
|
+
| `cos_f16_sve` | ✳️✳️📏 | Arm SVE | |
|
|
63
|
+
| `cos_f16x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
|
|
64
|
+
| `cos_i8x16_neon` | ✳️✳️📏 | Arm NEON | `d % 16 == 0` |
|
|
65
|
+
| `cos_f32x4_neon` | ✳️✳️📏 | Arm NEON | `d % 4 == 0` |
|
|
66
|
+
| `cos_f16x16_avx512` | ✳️✳️📏 | x86 AVX-512 | `d % 16 == 0` |
|
|
67
|
+
| `cos_f32x4_avx2` | ✳️✳️📏 | x86 AVX2 | `d % 4 == 0` |
|
|
68
|
+
| `l2sq_f32_sve` | ✳️✳️📏 | Arm SVE | |
|
|
69
|
+
| `l2sq_f16_sve` | ✳️✳️📏 | Arm SVE | |
|
|
70
|
+
| `hamming_b1x8_sve` | ✳️✳️📏 | Arm SVE | `d % 8 == 0` |
|
|
71
|
+
| `hamming_b1x128_sve` | ✳️✳️📏 | Arm SVE | `d % 128 == 0` |
|
|
72
|
+
| `hamming_b1x128_avx512` | ✳️✳️📏 | x86 AVX-512 | `d % 128 == 0` |
|
|
73
|
+
| `tanimoto_b1x8_naive` | ✳️✳️📏 | | `d % 8 == 0` |
|
|
74
|
+
| `tanimoto_maccs_naive` | ✳️✳️ | | `d == 166` |
|
|
75
|
+
| `tanimoto_maccs_neon` | ✳️✳️ | Arm NEON | `d == 166` |
|
|
76
|
+
| `tanimoto_maccs_sve` | ✳️✳️ | Arm SVE | `d == 166` |
|
|
77
|
+
| `tanimoto_maccs_avx512` | ✳️✳️ | x86 AVX-512 | `d == 166` |
|
|
63
78
|
|
|
64
|
-
|
|
65
|
-
With AVX2 and 256-bit registers the results should be better, but would be less broadly applicable.
|
|
79
|
+
## Benchmarks
|
|
66
80
|
|
|
67
|
-
|
|
81
|
+
The benchmarks are repeated for every function with a different number of cores involved.
|
|
82
|
+
Light-weight distance functions would be memory bound, implying that multi-core performance may be lower, if the bus bandwidth is not enough to saturate all the cores.
|
|
83
|
+
Similarly, heavy-weight distance functions running on all cores may result in CPU frequency downclocking.
|
|
84
|
+
This is well illustrated by the single-core performance of `i9-13950HX`, equipped with DDR5 memory.
|
|
85
|
+
|
|
86
|
+
| Method | Threads | Speed on 1024b |
|
|
87
|
+
| :--------------------- | ------: | -------------: |
|
|
88
|
+
| `tanimoto_maccs_naive` | 1 | 2.8 Gb/s |
|
|
89
|
+
| `tanimoto_maccs_naive` | 32 | 1.2 Gb/s |
|
|
90
|
+
| `cos_f32_naive` | 1 | 15.3 Gb/s |
|
|
91
|
+
| `cos_f32_naive` | 32 | 4.5 Gb/s |
|
|
92
|
+
| `dot_f32x4_avx2` | 1 | 96.2 Gb/s |
|
|
93
|
+
| `dot_f32x4_avx2` | 32 | 23.6 Gb/s |
|
|
94
|
+
| `cos_f32x4_avx2` | 1 | 56.3 Gb/s |
|
|
95
|
+
| `cos_f32x4_avx2` | 32 | 13.9 Gb/s |
|
|
68
96
|
|
|
69
97
|
To replicate on your hardware, please run following on Linux:
|
|
70
98
|
|
|
71
99
|
```sh
|
|
100
|
+
git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
|
|
72
101
|
cmake -DCMAKE_BUILD_TYPE=Release -DSIMSIMD_BUILD_BENCHMARKS=1 -B ./build && make -C ./build && ./build/simsimd_bench
|
|
73
102
|
```
|
|
74
103
|
|
|
@@ -76,10 +105,17 @@ MacOS:
|
|
|
76
105
|
|
|
77
106
|
```sh
|
|
78
107
|
brew install llvm
|
|
108
|
+
git clone https://github.com/ashvardanian/SimSIMD.git && cd SimSIMD
|
|
79
109
|
cmake -B ./build \
|
|
80
110
|
-DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \
|
|
81
111
|
-DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \
|
|
82
112
|
-DSIMSIMD_BUILD_BENCHMARKS=1 \
|
|
83
113
|
&& \
|
|
84
114
|
make -C ./build -j && ./build/simsimd_bench
|
|
85
|
-
```
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Install and test locally:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
pip install -e . && pytest python/test.py -s -x
|
|
121
|
+
```
|
package/simsimd/bench.cxx
CHANGED
|
@@ -3,16 +3,24 @@
|
|
|
3
3
|
#include <benchmark/benchmark.h>
|
|
4
4
|
|
|
5
5
|
#include <simsimd/simsimd.h>
|
|
6
|
+
#include <simsimd/simsimd_chem.h>
|
|
6
7
|
|
|
7
8
|
namespace bm = benchmark;
|
|
8
9
|
|
|
9
10
|
static const std::size_t threads_k = std::thread::hardware_concurrency();
|
|
10
|
-
static
|
|
11
|
+
static constexpr std::size_t time_k = 10;
|
|
12
|
+
static constexpr std::size_t bytes_k = 1024;
|
|
11
13
|
|
|
12
|
-
template <typename
|
|
13
|
-
|
|
14
|
+
template <typename return_at, typename... args_at>
|
|
15
|
+
constexpr std::size_t number_of_arguments(return_at (*f)(args_at...)) {
|
|
16
|
+
return sizeof...(args_at);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
template <typename scalar_at, std::size_t bytes_per_vector_ak = bytes_k,
|
|
20
|
+
typename metric_at = void> //
|
|
14
21
|
static void measure(bm::State& state, metric_at metric) {
|
|
15
22
|
|
|
23
|
+
constexpr ::size_t dimensions_ak = bytes_per_vector_ak / sizeof(scalar_at);
|
|
16
24
|
alignas(64) scalar_at a[dimensions_ak]{};
|
|
17
25
|
alignas(64) scalar_at b[dimensions_ak]{};
|
|
18
26
|
float c{};
|
|
@@ -20,15 +28,37 @@ static void measure(bm::State& state, metric_at metric) {
|
|
|
20
28
|
std::fill_n(a, dimensions_ak, static_cast<scalar_at>(1));
|
|
21
29
|
std::fill_n(b, dimensions_ak, static_cast<scalar_at>(2));
|
|
22
30
|
|
|
31
|
+
std::size_t iterations = 0;
|
|
23
32
|
for (auto _ : state)
|
|
24
|
-
|
|
33
|
+
if constexpr (number_of_arguments(metric_at{}) == 3)
|
|
34
|
+
bm::DoNotOptimize((c = metric(a, b, dimensions_ak))), iterations++;
|
|
35
|
+
else
|
|
36
|
+
bm::DoNotOptimize((c = metric(a, b))), iterations++;
|
|
37
|
+
|
|
38
|
+
state.counters["bytes"] = bm::Counter(iterations * bytes_per_vector_ak * 2u, bm::Counter::kIsRate);
|
|
39
|
+
state.counters["pairs"] = bm::Counter(iterations, bm::Counter::kIsRate);
|
|
40
|
+
}
|
|
25
41
|
|
|
26
|
-
|
|
27
|
-
|
|
42
|
+
template <typename scalar_at, std::size_t bytes_per_vector_ak = bytes_k, typename metric_at = void>
|
|
43
|
+
void register_(char const* name, metric_at distance_func) {
|
|
44
|
+
bm::RegisterBenchmark(name, measure<scalar_at, bytes_per_vector_ak, metric_at>, distance_func)
|
|
45
|
+
->Threads(1)
|
|
46
|
+
->MinTime(time_k);
|
|
47
|
+
bm::RegisterBenchmark(name, measure<scalar_at, bytes_per_vector_ak, metric_at>, distance_func)
|
|
48
|
+
->Threads(threads_k)
|
|
49
|
+
->MinTime(time_k);
|
|
28
50
|
}
|
|
29
51
|
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
simsimd_f32_t cos_f32_naive(simsimd_f32_t* v1, simsimd_f32_t* v2, std::size_t n) {
|
|
53
|
+
simsimd_f32_t inner_product = 0;
|
|
54
|
+
simsimd_f32_t magnitude1 = 0;
|
|
55
|
+
simsimd_f32_t magnitude2 = 0;
|
|
56
|
+
for (std::size_t i = 0; i != n; ++i) {
|
|
57
|
+
inner_product += v1[i] * v2[i];
|
|
58
|
+
magnitude1 += v1[i] * v1[i];
|
|
59
|
+
magnitude2 += v2[i] * v2[i];
|
|
60
|
+
}
|
|
61
|
+
return 1 - inner_product / (std::sqrt(magnitude1) * std::sqrt(magnitude2));
|
|
32
62
|
}
|
|
33
63
|
|
|
34
64
|
int main(int argc, char** argv) {
|
|
@@ -45,7 +75,7 @@ int main(int argc, char** argv) {
|
|
|
45
75
|
compiled_with_neon = true;
|
|
46
76
|
#endif
|
|
47
77
|
#if defined(__AVX2__)
|
|
48
|
-
|
|
78
|
+
compiled_with_avx2 = true;
|
|
49
79
|
#endif
|
|
50
80
|
#if defined(__AVX512VPOPCNTDQ__)
|
|
51
81
|
compiled_with_avx512popcnt = true;
|
|
@@ -59,6 +89,7 @@ int main(int argc, char** argv) {
|
|
|
59
89
|
std::printf("- Arm SVE support enabled: %s\n", flags[compiled_with_sve]);
|
|
60
90
|
std::printf("- x86 AVX2 support enabled: %s\n", flags[compiled_with_avx2]);
|
|
61
91
|
std::printf("- x86 AVX512VPOPCNTDQ support enabled: %s\n", flags[compiled_with_avx512popcnt]);
|
|
92
|
+
std::printf("Default vector length: %zu bytes\n", bytes_k);
|
|
62
93
|
std::printf("\n");
|
|
63
94
|
|
|
64
95
|
// Run the benchmarks
|
|
@@ -66,33 +97,41 @@ int main(int argc, char** argv) {
|
|
|
66
97
|
if (bm::ReportUnrecognizedArguments(argc, argv))
|
|
67
98
|
return 1;
|
|
68
99
|
|
|
100
|
+
register_<std::uint8_t, 21>("tanimoto_maccs_naive", simsimd_tanimoto_maccs_naive);
|
|
101
|
+
register_<simsimd_f32_t>("cos_f32_naive", cos_f32_naive);
|
|
102
|
+
|
|
69
103
|
#if defined(__ARM_FEATURE_SVE)
|
|
70
|
-
register_<simsimd_f32_t>("
|
|
71
|
-
register_<simsimd_f32_t>("
|
|
72
|
-
register_<
|
|
73
|
-
register_<
|
|
74
|
-
register_<std::
|
|
75
|
-
register_<std::uint8_t>("
|
|
104
|
+
register_<simsimd_f32_t>("dot_f32_sve", simsimd_dot_f32_sve);
|
|
105
|
+
register_<simsimd_f32_t>("cos_f32_sve", simsimd_cos_f32_sve);
|
|
106
|
+
register_<std::int16_t>("cos_f16_sve", simsimd_cos_f16_sve);
|
|
107
|
+
register_<simsimd_f32_t>("l2sq_f32_sve", simsimd_l2sq_f32_sve);
|
|
108
|
+
register_<std::int16_t>("l2sq_f16_sve", simsimd_l2sq_f16_sve);
|
|
109
|
+
register_<std::uint8_t>("hamming_b1x8_sve", simsimd_hamming_b1x8_sve);
|
|
110
|
+
register_<std::uint8_t>("hamming_b1x128_sve", simsimd_hamming_b1x128_sve);
|
|
111
|
+
register_<std::uint8_t, 21>("tanimoto_maccs_sve", simsimd_tanimoto_maccs_sve);
|
|
76
112
|
#endif
|
|
77
113
|
|
|
78
114
|
#if defined(__ARM_NEON)
|
|
79
|
-
register_<simsimd_f32_t>("
|
|
80
|
-
register_<std::int16_t>("
|
|
81
|
-
register_<std::int8_t>("
|
|
82
|
-
register_<simsimd_f32_t>("
|
|
115
|
+
register_<simsimd_f32_t>("dot_f32x4_neon", simsimd_dot_f32x4_neon);
|
|
116
|
+
register_<std::int16_t>("cos_f16x4_neon", simsimd_cos_f16x4_neon);
|
|
117
|
+
register_<std::int8_t>("cos_i8x16_neon", simsimd_cos_i8x16_neon);
|
|
118
|
+
register_<simsimd_f32_t>("cos_f32x4_neon", simsimd_cos_f32x4_neon);
|
|
119
|
+
register_<std::uint8_t, 21>("tanimoto_maccs_neon", simsimd_tanimoto_maccs_neon);
|
|
83
120
|
#endif
|
|
84
121
|
|
|
85
122
|
#if defined(__AVX2__)
|
|
86
|
-
register_<simsimd_f32_t>("
|
|
87
|
-
register_<
|
|
88
|
-
register_<simsimd_f32_t>("cos_f32x4avx2", simsimd_cos_f32x4avx2);
|
|
123
|
+
register_<simsimd_f32_t>("dot_f32x4_avx2", simsimd_dot_f32x4_avx2);
|
|
124
|
+
register_<simsimd_f32_t>("cos_f32x4_avx2", simsimd_cos_f32x4_avx2);
|
|
89
125
|
#endif
|
|
90
126
|
|
|
91
127
|
#if defined(__AVX512F__)
|
|
92
|
-
register_<std::int16_t>("
|
|
93
|
-
register_<std::uint8_t>("
|
|
128
|
+
register_<std::int16_t>("cos_f16x16_avx512", simsimd_cos_f16x16_avx512);
|
|
129
|
+
register_<std::uint8_t>("hamming_b1x128_avx512", simsimd_hamming_b1x128_avx512);
|
|
130
|
+
register_<std::uint8_t, 21>("tanimoto_maccs_avx512", simsimd_tanimoto_maccs_avx512);
|
|
94
131
|
#endif
|
|
95
132
|
|
|
133
|
+
|
|
134
|
+
|
|
96
135
|
bm::RunSpecifiedBenchmarks();
|
|
97
136
|
bm::Shutdown();
|
|
98
137
|
return 0;
|