我正在尝试将逻辑验证问题矢量化以在Intel 64上运行。
我将首先尝试描述问题:
我有一个70位整数的静态数组v[]
(其中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位FOUND
上检查appx 20%后,预计会满足v[]
条件。a
。v[]
的哪个元素匹配,只有那个元素匹配。a
只需要很少的内存,因此上次通话中留在L1中的任何内容都可能仍然存在。生成的代码旨在在支持SSE4.2,AVX指令的最新一代Intel Xeon处理器上运行。 我很乐意接受使用英特尔C编译器或至少GCC编译的汇编或C.
答案 0 :(得分:3)
这听起来像你真正需要的是一个更好的数据结构来存储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。