确保 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。在这里,我使用 Packet4f
和 Packet8f
定义了一个操作,然后使用大小为 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 进行修复。
我已经使用 Eigen 的工具编写了一些当前算法瓶颈的函数的矢量化版本。
我还通过确保在包含 Eigen 之后定义了 EIGEN_VECTORIZE_AVX
来检查是否启用了 AVX。
但是,如果数据大小不是 8 的倍数,我的函数似乎永远不会被调用 Packet8f
(AVX)。相反,它会被调用 Packet4f
(SSE) .
这是一个小的重现:https://gist.github.com/bitonic/e89561cb21837b4dee8b5f49e1303919。在这里,我使用 Packet4f
和 Packet8f
定义了一个操作,然后使用大小为 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 进行修复。