Eigen的矢量化后备如何工作?

时间:2017-06-26 13:02:51

标签: eigen simd

Eigen web site说:

  

对SSE 2/3/4,AVX,FMA,AVX512,ARM NEON(32位和64位),PowerPC AltiVec / VSX(32位和64位)指令集执行显式矢量化,以及现在是S390x SIMD(ZVector),可以优雅地回退到非矢量化代码。

这是否意味着你编译,例如使用FMA,并且您运行的CPU不支持它,它将回退到完全未启用的代码?或者它会回归到最好的矢量化吗?

如果没有,有没有办法让Eigen为所有或几个SIMD ISA编译并在运行时自动选择最佳?

编辑:要明确我说的是运行时回退。

1 个答案:

答案 0 :(得分:3)

在Eigen中绝对没有运行时调度。发生的一切都发生在编译时。这是您需要通过preprocessor macros that control the library's behavior或使用C ++编译器中的优化设置进行所有选择的地方。

为了实现运行时调度,您需要检查并查看每次调用库所支持的CPU功能并分支到适用的实现中,否则您将需要需要在启动时执行此检查并设置一个函数指针表(或一些其他方法来促进动态调度)。 Eigen不能做后者,因为它是一个只有头的库(只是一个类型和函数的集合),没有在初始化时调用的“main”函数,所有这些设置代码都可以被本地化。所以唯一的选择就是前者,这会导致显着的性能损失。这个图书馆的重点是速度;将这种类型的性能损失引入每个库的功能将是一场灾难。

该文档还包含a breakdown of how Eigen works, using a simple example。这个页面说:

  

本页的目标是理解Eigen如何编译它,假设启用了SSE2矢量化(GCC选项-msse2)。

这进一步证实了静态编译时选项决定了库如何工作的说法。

无论您选择哪个指令集,生成的代码都会包含这些指令。如果您尝试在不支持这些指令的处理器上执行该代码(例如,您在启用了AVX优化的情况下编译Eigen,但是在不支持AVX指令集的Intel Nehalem处理器上运行它),那么您将获得无效的指令异常(以任何形式提供给您的程序,操作系统通过CPU异常)。一旦你的CPU遇到一个无法识别/不支持的指令,就会发生这种情况,这些指令很可能在其中一个本征函数的内部深处(即,在启动时不会立即)。

然而,正如我在评论中所说,有一种回退机制,但它是静态的,都是在编译时完成的。作为the documentation indicates,Eigen支持多个向量指令集。如果选择最小公分母指令集(如SSE2),您仍将获得一定程度的矢量化。例如,虽然SSE3可以为某些特定任务提供专门的指令,但如果你不能以SSE3为目标,那么所有的希望都不会丢失。在许多地方,代码使用一系列SSE2指令来完成相同的任务。这些可能没有SSE3可用的那么高效,但它们仍然比没有任何矢量代码更快。您可以通过深入了解源代码来查看examples of this,特别是包含已针对不同指令集(通常使用内在函数)专门优化的花絮的arch文件夹。换句话说,您可以获得它为您的目标体系结构/指令集提供的最佳代码。