【问题标题】:x86-64 integer vectorisation optimisex86-64 整数向量化优化
【发布时间】:2012-10-04 18:27:10
【问题描述】:

我正在尝试对逻辑验证问题进行矢量化以在 Intel 64 上运行。

我将首先尝试描述问题:

我有一个静态数组 v[],包含 70 位整数(其中大约 400,000 个),它们在编译时都是已知的。

生产者创建 70 位整数 a,其中很多,非常快。

对于每个a,我需要确定是否存在来自v 的元素v[i] & a == 0

到目前为止,我在 C 中的实现是这样的(简化的):

for (; *v; v++) {
    if (!(a & *v))
        return FOUND;
}

// a had no matching element in v
return NOT_FOUND;

我正在考虑使用 SSE/AVX 对此进行优化,以加快流程并并行执行更多这些测试。我将a*v 分别加载到XMM 寄存器中并调用PTEST 指令进行验证。

我想知道是否有办法扩展它以使用新的YMM 寄存器的所有 256 位? 也许将 3x70 位打包到一个寄存器中? 我不太清楚如何有效地打包/解包它们,以证明每个测试不只使用一个寄存器。

我们对输入性质的了解:

  • v[] 中的所有元素都设置了很少的位
  • 不可能以任何方式置换/压缩 v[] 以使其使用少于 70 位
  • v[] 上平均检查大约 20% 后,FOUND 条件预计会得到满足。
  • 可以在批量检查之前缓冲多个a
  • 我不一定需要知道v[] 的哪个元素匹配,只要匹配或不匹配。
  • 生成a 需要的内存非常少,因此上次调用遗留在L1 中的任何内容都可能仍然存在。

生成的代码旨在在支持 SSE4.2、AVX 指令的最新一代英特尔至强处理器上运行。 我很乐意接受使用英特尔 C 编译器或至少 GCC 编译的程序集或 C。

【问题讨论】:

  • 如果你所做的只是一个简单的 AND'ing 操作,瓶颈很可能在生产者代码中。将 70 位数据打包成比特流将比仅检查它们是否为零更昂贵。
  • 另外,256 位整数运算在 AVX2 中。因此,您可能会混淆 256 位浮点按位指令,但它们的吞吐量低于 128 位整数按位指令。所以我怀疑强迫自己使用 256 位向量是否会有所帮助。
  • 确保v 中没有多余的值。如果(v[i] & v[j]) == v[i],则不需要测试v[j]
  • @ughoavgfhw 情况并非如此。 v[] 是 100% 非冗余、不可压缩的。
  • 这个问题已经在其他问题中讨论过:"efficiently find the first element matching a bit mask"。最有希望的是 wildplasser 的两个答案(一个很容易矢量化,另一个使用更优化的算法)。

标签: c optimization x86-64 sse vectorization


【解决方案1】:

听起来你真正需要的是一个更好的数据结构来存储 v[],这样搜索所花费的时间就少于线性时间。

考虑如果(v[0] & v[1]) & a 不为零,那么(v[0] & a)(v[1] & a) 都不能为零。这意味着可以创建一个树结构,其中 v[] 是叶子,父节点是其子节点的 AND 组合。然后,如果parentNode & a 给你一个非零值,你可以跳过看孩子。

但是,这不一定有帮助 - 父节点最终只会测试子节点之间的共同位,因此如果只有其中的几个,您最终仍会测试大量离开节点。但是,如果您可以在数据集中找到集群并将许多相似的 v[] 分组到一个共同的父节点下,这可能会大大减少您必须进行的比较次数。

另一方面,这样的树搜索涉及很多条件分支(昂贵),并且很难向量化。如果您可以只使用两个级别,我会首先尝试:首先在集群父节点之间进行矢量化搜索,然后为每个匹配项搜索该集群中的条目。


实际上这是另一个想法,以帮助解决 70 位不适合寄存器的事实: 您可以将 v[] 拆分为 64 (=2^6) 个不同的数组。在原始 v[] 中的 70 位中,最高 6 位用于确定哪个数组将包含该值,并且只有剩余的 64 位实际存储在数组中。

通过针对数组索引测试掩码 a,您将知道要搜索 64 个数组中的哪一个(在最坏的情况下,如果 a 没有设置 6 个最高位中的任何一个,那将全部),并且每个单独的数组搜索仅处理每个元素 64 位(更容易打包)。

事实上,第二种方法也可以推广到树结构中,这会给你某种trie

【讨论】:

  • 第一个想法可能会奏效,但我不确定效果如何。我刚刚重新检查了数据。 v[] 中的每个元素只设置了 4 位。它们作为置换群的轨道生成到 70 个元素上。最后一个想法很好地解决了 70 位问题,将只产生 1 个巨型数组(对于 0 的情况)和在其他情况下非常小的数组。 a 设置了 20 到 25 位
猜你喜欢
  • 2012-04-30
  • 2012-10-15
  • 2021-04-01
  • 2021-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
  • 2012-07-17
相关资源
最近更新 更多