Simsimd

Latest version: v6.2.1

Safety actively analyzes 706567 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 8 of 21

5.3.0

![set-intersections](https://github.com/user-attachments/assets/47f8f2fc-13c6-491d-8586-dea15e3d2241)


- Need to accelerate TF-IDF search ranking?
- Joining large tables in an OLAP database?
- Implementing graph algorithms?

Chances are - you need fast set intersections! It's one of the most common operations in programming, yet one of the hardest to accelerate with SIMD! This PR improves existing kernels and adds new ones for fast set intersections of _sorted arrays of unique_ `u16` and `u32` values. Now, SimSIMD is not practically the only production codebase to use Arm SVE, but also one of the first to use the new SVE2 instructions available on Graviton 4 AWS CPUs, and coming to Nvidia's Grace Hopper, Microsoft Cobalt, and Google Axios! So upgrade to v5.2 and let's make the databases & search systems go __5x faster__!

Speedups on x86

The new AVX-512 variant shows significant improvements in pairs/s across all benchmarks:

- For `|A|=128`, `|B|=128`, `|A∩B|=1`, pairs/s increased
- from **1.14M/s** in the old implementation
- to **7.73M/s** in the new one, a **6.7x improvement**.
- At `|A∩B|=64`, the pairs/s rose:
- from **1.13M/s** in the old implementation
- to **8.19M/s** in the new one, a **7.2x gain**.
- For larger sets, like `|A|=1024` and `|B|=8192`, with `|A∩B|=10`, pairs/s increased:
- from **130.18k/s** in the old implementation
- to **194.50k/s** in the new one, a **49% gain**.

However, in cases like `|A|=128`, `|B|=8192`, with `|A∩B|=64`, pairs/s slightly decreased from **369.7k/s** to **222.9k/s**. Overall, the new implementation outperforms the previous one, and **no case is worse than the serial version**.

Speedups on Arm

On the Arm architecture, similar performance gains were achieved using the NEON and SVE2 instruction sets:

- The optimized NEON implementation showed a 3.9x improvement in pairs/s for `|A|=128, |B|=128, |A∩B|=1`, going from 1.62M/s to 5.12M/s.
- For `|A∩B|=64` in the same configuration, performance improved from 1.60M/s to 5.51M/s, showing a 3.4x gain.
- The SVE2 implementation also outperformed the previous SVE setup, achieving 5.6M/s (NEON) versus 1.27M/s (SVE) for `|A|=128, |B|=128, |A∩B|=1`, a 4.4x improvement.
- In larger datasets, such as `|A|=1024` and `|B|=8192`, the pairs/s increased from 49.3k/s to 110.03k/s, with NEON, and further to 109.47k/s with SVE2, nearly doubling the performance.

x86 Benchmarking Setup

The benchmarking was conducted on `r7iz` AWS instances with Intel Sapphire Rapids CPUs.

sh
Running build_release/simsimd_bench
Run on (16 X 3900.51 MHz CPU s)
CPU Caches:
L1 Data 48 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 2048 KiB (x8)
L3 Unified 61440 KiB (x1)


Old Serial Baselines

sh
-----------------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
-----------------------------------------------------------------------------------------------------------------------------------------
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 567 ns 567 ns 24785678 pairs=1.76263M/s
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 567 ns 567 ns 24598141 pairs=1.76286M/s
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 569 ns 569 ns 24741572 pairs=1.75684M/s
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 568 ns 568 ns 24871638 pairs=1.76073M/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 2508 ns 2508 ns 5591748 pairs=398.803k/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 2509 ns 2509 ns 5589871 pairs=398.535k/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 2530 ns 2530 ns 5564535 pairs=395.33k/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 2522 ns 2522 ns 5532306 pairs=396.447k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 4791 ns 4791 ns 2920833 pairs=208.737k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 4800 ns 4800 ns 2923139 pairs=208.346k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 4821 ns 4820 ns 2906942 pairs=207.448k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 4843 ns 4843 ns 2897334 pairs=206.504k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 4484 ns 4484 ns 3122873 pairs=223.023k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 4479 ns 4479 ns 3124662 pairs=223.261k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 4484 ns 4484 ns 3125584 pairs=223.034k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 4500 ns 4500 ns 3104588 pairs=222.229k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 20118 ns 20117 ns 696244 pairs=49.7084k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 20134 ns 20134 ns 696160 pairs=49.6682k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 20125 ns 20124 ns 695799 pairs=49.6911k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 20102 ns 20102 ns 695762 pairs=49.7464k/s


Existing AVX-512 Implementation

sh
-------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
-------------------------------------------------------------------------------------------------------------------------------
intersect_u16_ice<|A|=128d,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 875 ns 875 ns 16248886 pairs=1.14342M/s
intersect_u16_ice<|A|=128d,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 873 ns 873 ns 16081249 pairs=1.14555M/s
intersect_u16_ice<|A|=128d,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 882 ns 882 ns 15851609 pairs=1.13354M/s
intersect_u16_ice<|A|=128d,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 916 ns 916 ns 15282595 pairs=1091.32k/s
intersect_u16_ice<|A|=128d,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 955 ns 955 ns 14660187 pairs=1047.53k/s
intersect_u16_ice<|A|=128d,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 955 ns 955 ns 14663375 pairs=1047.57k/s
intersect_u16_ice<|A|=128d,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 952 ns 952 ns 14702462 pairs=1050.17k/s
intersect_u16_ice<|A|=128d,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 949 ns 949 ns 14743103 pairs=1053.59k/s
intersect_u16_ice<|A|=128d,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 2718 ns 2718 ns 5168053 pairs=367.871k/s
intersect_u16_ice<|A|=128d,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 2698 ns 2698 ns 5155819 pairs=370.664k/s
intersect_u16_ice<|A|=128d,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 2705 ns 2705 ns 5203675 pairs=369.686k/s
intersect_u16_ice<|A|=128d,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 2693 ns 2693 ns 5187007 pairs=371.377k/s
intersect_u16_ice<|A|=1024d,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 7310 ns 7310 ns 1910292 pairs=136.8k/s
intersect_u16_ice<|A|=1024d,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 7312 ns 7312 ns 1913190 pairs=136.759k/s
intersect_u16_ice<|A|=1024d,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 7365 ns 7365 ns 1900946 pairs=135.781k/s
intersect_u16_ice<|A|=1024d,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 7439 ns 7439 ns 1882319 pairs=134.43k/s
intersect_u16_ice<|A|=1024d,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 7682 ns 7681 ns 1821784 pairs=130.183k/s
intersect_u16_ice<|A|=1024d,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 7695 ns 7695 ns 1821861 pairs=129.955k/s
intersect_u16_ice<|A|=1024d,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 7643 ns 7643 ns 1829955 pairs=130.842k/s
intersect_u16_ice<|A|=1024d,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 7617 ns 7617 ns 1838612 pairs=131.279k/s


New AVX-512 Implementation

sh
--------------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
--------------------------------------------------------------------------------------------------------------------------------------
intersect_u16_ice<|A|=128,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 129 ns 129 ns 101989513 pairs=7.72559M/s
intersect_u16_ice<|A|=128,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 134 ns 134 ns 107140278 pairs=7.46949M/s
intersect_u16_ice<|A|=128,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 122 ns 122 ns 113134485 pairs=8.18634M/s
intersect_u16_ice<|A|=128,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 114 ns 114 ns 122765163 pairs=8.75268M/s
intersect_u16_ice<|A|=128,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 1042 ns 1042 ns 13412933 pairs=959.711k/s
intersect_u16_ice<|A|=128,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 1035 ns 1035 ns 13423867 pairs=966.278k/s
intersect_u16_ice<|A|=128,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 1038 ns 1038 ns 13401265 pairs=963.267k/s
intersect_u16_ice<|A|=128,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 1055 ns 1055 ns 13170438 pairs=948.193k/s
intersect_u16_ice<|A|=128,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 4315 ns 4315 ns 3024069 pairs=231.776k/s
intersect_u16_ice<|A|=128,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 3999 ns 3999 ns 3371134 pairs=250.088k/s
intersect_u16_ice<|A|=128,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 4486 ns 4486 ns 3278143 pairs=222.9k/s
intersect_u16_ice<|A|=128,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 4525 ns 4525 ns 3170802 pairs=220.991k/s
intersect_u16_ice<|A|=1024,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 817 ns 817 ns 17102654 pairs=1.22419M/s
intersect_u16_ice<|A|=1024,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 820 ns 820 ns 17168886 pairs=1.22003M/s
intersect_u16_ice<|A|=1024,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 793 ns 793 ns 17756237 pairs=1.26107M/s
intersect_u16_ice<|A|=1024,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 747 ns 747 ns 18261381 pairs=1.33794M/s
intersect_u16_ice<|A|=1024,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 5142 ns 5142 ns 2728465 pairs=194.496k/s
intersect_u16_ice<|A|=1024,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 5114 ns 5114 ns 2727670 pairs=195.56k/s
intersect_u16_ice<|A|=1024,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 5142 ns 5142 ns 2716714 pairs=194.491k/s
intersect_u16_ice<|A|=1024,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 5151 ns 5151 ns 2721708 pairs=194.148k/s


Arm Benchmarking Setup

The benchmarking was conducted on `r8g` AWS instances with Graviton 4 CPUs.

sh
Running build_release/simsimd_bench
Run on (2 X 2000 MHz CPU s)
CPU Caches:
L1 Data 64 KiB (x2)
L1 Instruction 64 KiB (x2)
L2 Unified 2048 KiB (x2)
L3 Unified 36864 KiB (x1)


Old Serial Baselines

sh
----------------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
----------------------------------------------------------------------------------------------------------------------------------------
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 615 ns 614 ns 22780083 pairs=1.62833M/s
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 610 ns 608 ns 22727971 pairs=1.64341M/s
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 622 ns 622 ns 22356453 pairs=1.60786M/s
intersect_u16_serial<|A|=128,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 679 ns 679 ns 20641056 pairs=1.47332M/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 2542 ns 2542 ns 5511491 pairs=393.332k/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 2539 ns 2539 ns 5512132 pairs=393.822k/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 2535 ns 2535 ns 5511950 pairs=394.436k/s
intersect_u16_serial<|A|=128,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 2546 ns 2546 ns 5504586 pairs=392.843k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 4122 ns 4122 ns 3374465 pairs=242.586k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 4117 ns 4117 ns 3372418 pairs=242.884k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 4138 ns 4138 ns 3374977 pairs=241.657k/s
intersect_u16_serial<|A|=128,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 4142 ns 4142 ns 3361656 pairs=241.412k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 4569 ns 4564 ns 3072148 pairs=219.129k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 4557 ns 4557 ns 3075313 pairs=219.419k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 4577 ns 4577 ns 3052064 pairs=218.472k/s
intersect_u16_serial<|A|=1024,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 4728 ns 4728 ns 2980530 pairs=211.504k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 20278 ns 20273 ns 690191 pairs=49.3276k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 21192 ns 20272 ns 691680 pairs=49.3302k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 21438 ns 20268 ns 689617 pairs=49.3384k/s
intersect_u16_serial<|A|=1024,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 22010 ns 20317 ns 692675 pairs=49.2207k/s


Old SVE Implementation

sh
-------------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
-------------------------------------------------------------------------------------------------------------------------------------
intersect_u16_sve<|A|=128,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 794 ns 788 ns 17715501 pairs=1.26918M/s
intersect_u16_sve<|A|=128,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 809 ns 785 ns 17579527 pairs=1.27438M/s
intersect_u16_sve<|A|=128,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 819 ns 810 ns 17229391 pairs=1.23482M/s
intersect_u16_sve<|A|=128,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 878 ns 856 ns 16347952 pairs=1.16827M/s
intersect_u16_sve<|A|=128,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 1475 ns 1380 ns 10129190 pairs=724.869k/s
intersect_u16_sve<|A|=128,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 1400 ns 1361 ns 10312201 pairs=734.514k/s
intersect_u16_sve<|A|=128,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 1353 ns 1344 ns 10427410 pairs=743.793k/s
intersect_u16_sve<|A|=128,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 1369 ns 1350 ns 10516190 pairs=740.815k/s
intersect_u16_sve<|A|=128,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 7156 ns 7009 ns 1991602 pairs=142.677k/s
intersect_u16_sve<|A|=128,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 7095 ns 6982 ns 2006057 pairs=143.232k/s
intersect_u16_sve<|A|=128,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 7328 ns 6967 ns 2004803 pairs=143.537k/s
intersect_u16_sve<|A|=128,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 6966 ns 6963 ns 2013422 pairs=143.624k/s
intersect_u16_sve<|A|=1024,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 7119 ns 6517 ns 2143784 pairs=153.437k/s
intersect_u16_sve<|A|=1024,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 6978 ns 6522 ns 2146331 pairs=153.331k/s
intersect_u16_sve<|A|=1024,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 6721 ns 6533 ns 2141325 pairs=153.067k/s
intersect_u16_sve<|A|=1024,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 7046 ns 6675 ns 2095016 pairs=149.823k/s
intersect_u16_sve<|A|=1024,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 10819 ns 10722 ns 1307796 pairs=93.2695k/s
intersect_u16_sve<|A|=1024,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 11295 ns 10729 ns 1305575 pairs=93.2031k/s
intersect_u16_sve<|A|=1024,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 10596 ns 10596 ns 1317798 pairs=94.3769k/s
intersect_u16_sve<|A|=1024,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 10527 ns 10486 ns 1337148 pairs=95.3626k/s


New NEON Implementation

sh
--------------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
--------------------------------------------------------------------------------------------------------------------------------------
intersect_u16_neon<|A|=128,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 195 ns 195 ns 72473251 pairs=5.12346M/s
intersect_u16_neon<|A|=128,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 193 ns 193 ns 71826322 pairs=5.17983M/s
intersect_u16_neon<|A|=128,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 181 ns 181 ns 76859132 pairs=5.51211M/s
intersect_u16_neon<|A|=128,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 161 ns 161 ns 86301671 pairs=6.22906M/s
intersect_u16_neon<|A|=128,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 1199 ns 1027 ns 13866808 pairs=973.295k/s
intersect_u16_neon<|A|=128,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 1171 ns 1034 ns 13729254 pairs=966.886k/s
intersect_u16_neon<|A|=128,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 1120 ns 1038 ns 13671085 pairs=963.804k/s
intersect_u16_neon<|A|=128,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 1150 ns 1051 ns 13070692 pairs=951.238k/s
intersect_u16_neon<|A|=128,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 2587 ns 2446 ns 5685615 pairs=408.885k/s
intersect_u16_neon<|A|=128,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 2595 ns 2490 ns 5538880 pairs=401.615k/s
intersect_u16_neon<|A|=128,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 2482 ns 2460 ns 5704185 pairs=406.459k/s
intersect_u16_neon<|A|=128,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 2512 ns 2512 ns 5592948 pairs=398.064k/s
intersect_u16_neon<|A|=1024,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 1599 ns 1573 ns 8893290 pairs=635.781k/s
intersect_u16_neon<|A|=1024,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 1570 ns 1570 ns 8950291 pairs=637.098k/s
intersect_u16_neon<|A|=1024,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 1488 ns 1488 ns 9449103 pairs=672.121k/s
intersect_u16_neon<|A|=1024,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 1332 ns 1332 ns 10582682 pairs=751.007k/s
intersect_u16_neon<|A|=1024,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 8997 ns 8997 ns 1556944 pairs=111.144k/s
intersect_u16_neon<|A|=1024,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 8999 ns 8999 ns 1554324 pairs=111.128k/s
intersect_u16_neon<|A|=1024,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 9126 ns 9070 ns 1543769 pairs=110.257k/s
intersect_u16_neon<|A|=1024,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 9089 ns 9089 ns 1536462 pairs=110.029k/s


New SVE2 Implementation

sh
--------------------------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
--------------------------------------------------------------------------------------------------------------------------------------
intersect_u16_sve2<|A|=128,|B|=128,|A∩B|=1>/min_time:10.000/threads:1 179 ns 178 ns 77997900 pairs=5.60245M/s
intersect_u16_sve2<|A|=128,|B|=128,|A∩B|=6>/min_time:10.000/threads:1 179 ns 179 ns 77959137 pairs=5.59776M/s
intersect_u16_sve2<|A|=128,|B|=128,|A∩B|=64>/min_time:10.000/threads:1 170 ns 170 ns 82829421 pairs=5.88598M/s
intersect_u16_sve2<|A|=128,|B|=128,|A∩B|=121>/min_time:10.000/threads:1 143 ns 143 ns 97771708 pairs=6.9995M/s
intersect_u16_sve2<|A|=128,|B|=1024,|A∩B|=1>/min_time:10.000/threads:1 900 ns 900 ns 15430306 pairs=1.11111M/s
intersect_u16_sve2<|A|=128,|B|=1024,|A∩B|=6>/min_time:10.000/threads:1 909 ns 909 ns 15374525 pairs=1099.58k/s
intersect_u16_sve2<|A|=128,|B|=1024,|A∩B|=64>/min_time:10.000/threads:1 922 ns 922 ns 15025863 pairs=1085.12k/s
intersect_u16_sve2<|A|=128,|B|=1024,|A∩B|=121>/min_time:10.000/threads:1 932 ns 932 ns 15083373 pairs=1072.6k/s
intersect_u16_sve2<|A|=128,|B|=8192,|A∩B|=1>/min_time:10.000/threads:1 2135 ns 2135 ns 6460842 pairs=468.333k/s
intersect_u16_sve2<|A|=128,|B|=8192,|A∩B|=6>/min_time:10.000/threads:1 2118 ns 2118 ns 6509484 pairs=472.238k/s
intersect_u16_sve2<|A|=128,|B|=8192,|A∩B|=64>/min_time:10.000/threads:1 2138 ns 2138 ns 6468742 pairs=467.706k/s
intersect_u16_sve2<|A|=128,|B|=8192,|A∩B|=121>/min_time:10.000/threads:1 2136 ns 2136 ns 6419653 pairs=468.097k/s
intersect_u16_sve2<|A|=1024,|B|=1024,|A∩B|=10>/min_time:10.000/threads:1 1502 ns 1502 ns 9329372 pairs=665.698k/s
intersect_u16_sve2<|A|=1024,|B|=1024,|A∩B|=51>/min_time:10.000/threads:1 1492 ns 1492 ns 9375601 pairs=670.246k/s
intersect_u16_sve2<|A|=1024,|B|=1024,|A∩B|=512>/min_time:10.000/threads:1 1416 ns 1416 ns 9859829 pairs=706.16k/s
intersect_u16_sve2<|A|=1024,|B|=1024,|A∩B|=972>/min_time:10.000/threads:1 1274 ns 1274 ns 11052636 pairs=785.05k/s
intersect_u16_sve2<|A|=1024,|B|=8192,|A∩B|=10>/min_time:10.000/threads:1 9148 ns 9148 ns 1528714 pairs=109.319k/s
intersect_u16_sve2<|A|=1024,|B|=8192,|A∩B|=51>/min_time:10.000/threads:1 9150 ns 9150 ns 1529679 pairs=109.287k/s
intersect_u16_sve2<|A|=1024,|B|=8192,|A∩B|=512>/min_time:10.000/threads:1 9148 ns 9147 ns 1527762 pairs=109.32k/s
intersect_u16_sve2<|A|=1024,|B|=8192,|A∩B|=972>/min_time:10.000/threads:1 9135 ns 9135 ns 1529316 pairs=109.473k/s

5.2.1

5.2.0

Performance Improvements

The older `bf16` Euclidean Distance implementation had an inefficient implementation for mixed-precision vector subtractions. The new one is very similar, but avoids a couple of serial operations and doubles the throughput:

c
SIMSIMD_INTERNAL __m512i simsimd_substract_bf16x32_genoa(__m512i a_i16, __m512i b_i16) {
union {
__m512 fvec;
__m512i ivec;
simsimd_f32_t f32[16];
simsimd_u16_t u16[32];
simsimd_bf16_t bf16[32];
} d_odd, d_even, d, a_f32_even, b_f32_even, d_f32_even, a_f32_odd, b_f32_odd, d_f32_odd, a, b;
a.ivec = a_i16;
b.ivec = b_i16;
a_f32_odd.ivec = _mm512_and_si512(a_i16, _mm512_set1_epi32(0xFFFF0000));
a_f32_even.ivec = _mm512_slli_epi32(a_i16, 16);
b_f32_odd.ivec = _mm512_and_si512(b_i16, _mm512_set1_epi32(0xFFFF0000));
b_f32_even.ivec = _mm512_slli_epi32(b_i16, 16);
d_f32_odd.fvec = _mm512_sub_ps(a_f32_odd.fvec, b_f32_odd.fvec);
d_f32_even.fvec = _mm512_sub_ps(a_f32_even.fvec, b_f32_even.fvec);
d_f32_even.ivec = _mm512_srli_epi32(d_f32_even.ivec, 16);
d.ivec = _mm512_mask_blend_epi16(0x55555555, d_f32_odd.ivec, d_f32_even.ivec);
return d.ivec;
}


Old Implementation

sh
-----------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
-----------------------------------------------------------------------------------------------------------
l2sq_bf16_haswell_128d/min_time:10.000/threads:1 15.2 ns 15.2 ns 890417569 abs_delta=41.5895n bytes=33.6296G/s pairs=65.6828M/s relative_error=20.6195n
l2sq_bf16_genoa_128d/min_time:10.000/threads:1 16.3 ns 16.3 ns 867745590 abs_delta=7.74925m bytes=31.3522G/s pairs=61.2348M/s relative_error=3.87658m
l2sq_bf16_serial_128d/min_time:10.000/threads:1 599 ns 599 ns 23382373 abs_delta=489.092n bytes=855.039M/s pairs=1.67M/s relative_error=244.952n


New Implementation

sh
-----------------------------------------------------------------------------------------------------------
Benchmark Time CPU Iterations UserCounters...
-----------------------------------------------------------------------------------------------------------
l2sq_bf16_haswell_128d/min_time:10.000/threads:1 14.7 ns 14.7 ns 952634662 abs_delta=37.4399n bytes=34.7926G/s pairs=67.9544M/s relative_error=18.9709n
l2sq_bf16_genoa_128d/min_time:10.000/threads:1 8.45 ns 8.45 ns 1000000000 abs_delta=7.70743m bytes=60.5856G/s pairs=118.331M/s relative_error=3.85599m
l2sq_bf16_serial_128d/min_time:10.000/threads:1 599 ns 599 ns 23376884 abs_delta=471.586n bytes=854.885M/s pairs=1.6697M/s relative_error=236.592n


Other Changes

- rschu1ze added a very handy feature-detection function `simsimd_uses_dynamic_dispatch()` 🙌 Do we need to expose it to Rust, Python, and other bindings?
- MarkReedZ added missing kernels to the benchmark utility 🙌

5.1.4

5.1.3

5.1.2

Page 8 of 21

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.