使用 F# 和 SIMD 搜索值索引

Posted

技术标签:

【中文标题】使用 F# 和 SIMD 搜索值索引【英文标题】:Using F# and SIMD to search for index of value 【发布时间】:2021-08-22 05:27:14 【问题描述】:

我正在研究一种算法,用于搜索数组以查找给定值的索引。我正在尝试遵循.NET Core CLR 中的类似技术。

我感到困惑的是调用BitOperations.TrailingZeroCount 返回的idx 的值。当我搜索2 时,它应该为我正在搜索的数据返回一个索引值1。我得到的是4。我是否需要将字节偏移量转换回实际类型?这是写这个最有效的方法吗?关于在 .NET 中使用内部函数的文档并不多。

open System
open System.Runtime.Intrinsics.X86
open System.Runtime.Intrinsics
open System.Numerics

#nowarn "9"
#nowarn "20"

[<EntryPoint>]
let main argv =

    let searchSpace : Span<int32> = Span [| 1 .. 8 |]
    let pSearchSpace = && (searchSpace.GetPinnableReference ())
    let search = Sse2.LoadVector128 (pSearchSpace)

    let value = 2
    let values = Vector128.Create value

    let comparison = Sse2.CompareEqual (values, search)
    let matches = Sse2.MoveMask (comparison.AsByte())
    
    if matches > 0 then
        let idx = BitOperations.TrailingZeroCount matches
        printfn "%A" idx // <--- This prints 4 instead of 1

    0 // return an integer exit code

【问题讨论】:

顺便说一句,如果您使用的是 256 位向量,您可能需要if matches != 0vpmovmskb 会给你一个 32 位的位掩码,所以可以设置符号位。此外,如果您正在线性搜索大于 1 个向量的数组,并且预计第一个匹配不会立即出现,您可能希望将一些比较结果组合在一起,例如 glibc memchr 的做法 (code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/…),然后整理出来当您知道 2 或 4 个向量(1 或 2 个缓存行)中存在一个时,匹配的位置。 这正是我所期待的。我一直在研究 SIMD 以快速搜索 int 数组以找到特定值的索引。在我的情况下,数组已排序并且值是唯一的。数组的大小可能在 1K - 10K 元素的范围内。 数组已排序?所以你在二进制搜索让你接近之后使用它?或者您正在使用隐式 quint-tree 或带有 SIMD 的东西来决定接下来要下降 5 个子树中的哪一个...What is the most efficient way to implement a BST in such a way the find(value) function is optimized for random values in the tree on x86? SIMD 对 1k 元素的线性搜索甚至可能不如普通的二进制搜索好。 (如果您希望数据在缓存中很热,请使其无分支。) 问题的完整描述是我有两个数组,A和B。两者都是唯一int的排序数组。对于 A 中的每个元素,我需要在 B 中找到匹配项的索引。由于它们是排序的,我想利用我只需要为 A 中的每个剩余元素搜索 B 中的剩余值。我一直查看 SIMD 以同时执行许多比较。 我明白了。也许蛮力 pcmpgtd 搜索,直到找到更大的,然后 pcmpeqd 看看最后一个向量中是否有匹配项。然后你不会一直走到最后,如果元素存在的话,你就不会走到最后。 【参考方案1】:

Sse2.MoveMask (comparison.AsByte())(即vpmovmskb)为每个 int32 匹配结果提供 4 个掩码位,按照您的要求从每个字节中获得一个。

要么使用vmovmskps(也许是MoveMask(cmp.AsFloat()),如果F# 是这样做的?)或者处理从bsf / tzcnt 获得的字节而不是元素索引。

【讨论】:

以上是关于使用 F# 和 SIMD 搜索值索引的主要内容,如果未能解决你的问题,请参考以下文章

是否有 SIMD 指令来实现批量数组内存索引映射?

Rust 获取 SIMD 向量中真实字节的索引

具有重复值的列上的数据库索引

使用 SIMD 找出两个元素的最大差异

F# list 查找项目索引

用于全文搜索的 SQL Server 索引视图