确保 Eigen 对某个操作使用 AVX 向量化

Ensuring that Eigen uses AVX vectorization for a certain operation

我已经使用 Eigen 的工具编写了一些当前算法瓶颈的函数的矢量化版本。

我还通过确保在包含 Eigen 之后定义了 EIGEN_VECTORIZE_AVX 来检查是否启用了 AVX。

但是,如果数据大小不是 8 的倍数,我的函数似乎永远不会被调用 Packet8f (AVX)。相反,它会被调用 Packet4f (SSE) .

这是一个小的重现:https://gist.github.com/bitonic/e89561cb21837b4dee8b5f49e1303919。在这里,我使用 Packet4fPacket8f 定义了一个操作,然后使用大小为 8 和 9 的数组计算每个操作被调用的次数。当数组大小为 8 时,Packet8f正如预期的那样,version 被调用一次。当它的大小为 9 时,Packet4f 版本被调用两次,外加一次对非矢量化版本的调用。我已经在 Eigen 当前的 master 1d0c45122a5c4c5c1c4309f904120e551bacad02.

上测试了这段代码

我已经挖掘了一下,我相信数据包选择发生在这里:https://gitlab.com/libeigen/eigen/blob/1d0c45122a5c4c5c1c4309f904120e551bacad02/Eigen/src/Core/util/XprHelper.h#L197 .

如果我没理解错的话,如果数据的大小不是动态的,不是8的倍数(也就是unpacket_traits<Packet8f>::size的值),会选择half-packet,与reproduction匹配以上显示。

如果我的理解是正确的,为什么会这样呢?不应该选择完整的数据包,其余元素使用非矢量化操作吗?

会不会是条件不对,应该是 >= 比较,例如像

template<int Size, typename PacketType,
         bool Stop = Size==Dynamic || Size >= unpacket_traits<PacketType>::size || is_same<PacketType,typename unpacket_traits<PacketType>::half>::value>
struct find_best_packet_helper;

而不是

template<int Size, typename PacketType,
         bool Stop = Size==Dynamic || (Size%unpacket_traits<PacketType>::size)==0 || is_same<PacketType,typename unpacket_traits<PacketType>::half>::value>
struct find_best_packet_helper;

我已经确认通过上述修复问题消失了。

但是我可能误解了这里发生的事情,因为我不是很精通 Eigen 的内部结构。

我已经确认这是由于 Eigen 选择数据包类型的方式造成的,请参阅 https://gitlab.com/libeigen/eigen/merge_requests/46 进行修复。