Eigen 的矢量化回退如何工作?

Posted

技术标签:

【中文标题】Eigen 的矢量化回退如何工作?【英文标题】:How does Eigen's vectorisation fallback work? 【发布时间】:2017-06-26 13:02:50 【问题描述】:

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 编译并在运行时自动选择最好的?

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

【问题讨论】:

鉴于the linked FAQ 说,“使用 SSE,至少需要 SSE2。SSE3、SSSE3 和 SSE4 是可选的,如果启用它们将自动使用。”,我怀疑它会退回到可用的最佳矢量化选项。但是仍然会有硬性限制。例如,您不能在没有至少 SSE2 的情况下对双精度浮点运算进行矢量化。 SSE 仅支持单精度。我认为这就是报价中要求背后的原因。 你可以通过digging into the source code看到这个。在已针对 SSE 优化的版本链接功能中,您可以看到有 SSE3 的实现,但是当它不可用时,它会回退到仅需要 SSE2 的版本。这是使用预处理器宏选择的,因此您需要确保正确定义这些宏。 那些似乎是编译时预处理器指令。我说的是 run-time 后备。 我绝对没有看到任何迹象表明,无论是在代码中还是在文档中,Eigen 支持任何类型的运行时调度/委托。你从哪里得到它的想法? (但是请注意,一些 编译器 支持这些功能,例如 Intel 的 C 编译器。因此,由于这是一个仅头文件库,您可以使用其中一个编译器对其进行编译,并可能获得运行时调度。) 来自我发布的报价。如果它是在谈论运行时或编译时,这是模棱两可的。这是我问题的重点!! 【参考方案1】:

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

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

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

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

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

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

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

【讨论】:

以上是关于Eigen 的矢量化回退如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

Visual Studio 2012 中 Eigen 类型向量的自动向量化效果不佳

为啥库需要硬编码矢量化而不是编译器自动矢量化

如何在 iPhone 中编译 Eigen

Eigen的速度为啥这么快

如何使用条件有效地向量化多项式计算(屋顶线模型)

Eigen::Vector3f 对齐