C++26 中 std::simd 的争议

C++26 中 std::simd 的争议

C++26 的到来带来了一个新的标准化的 SIMD(单指令多数据)库,std::simd。虽然向量化的标准化是一个追求了十多年的目标,但其实现形式让许多高性能计算(HPC)社区的人感到怀疑。核心矛盾在于对可移植的高层抽象的渴望与进行严肃 SIMD 工作所需的极端优化之间的必要性。

可移植向量化的承诺

多年来,C++ 开发者不得不在这两者之间做出选择:依赖编译器的自动向量化(这通常是不可预测且脆弱的)或者编写特定于硬件的 intrinsics。Intrinsics 可以提供尽可能高的性能,但它们将代码与特定架构(例如 x86 AVX-512 或 ARM NEON/SVE)绑定在一起。

std::simd 旨在通过提供一个可移植的接口来弥补这一差距。其目标是允许开发者编写一次向量代码,并使其映射到目标硬件上最高效的指令。理论上,这减轻了可移植性的负担,并允许编译器处理类型和宽度到特定微架构的映射。

反对意见:为什么抽象会使 SIMD 失效

批评者认为,通用库不可能捕捉到现代硬件的细微差别。SIMD 性能不仅仅是将 loadadd 操作映射到向量寄存器;它还在于理解特定微架构的延迟、吞吐量和特定的指令集。

正如一位经验丰富的 SIMD 开发者所指出的:

每一个抽象,包括自动向量化,在狭窄的案例之外通常都相当糟糕,因为它们无法(且大多无法)捕捉到使用 intrinsics 以及它们在不同微架构之间极大的差异所能实现的可能性。如果我想要好的结果,我必须编写 intrinsics。

从这个角度来看,std::simd 提供的可移植性是一个会放大性能损失的“差距”。对于那些从事“严肃工作”的 SIMD 开发者来说,精确控制硬件的能力是首要要求,而一个隐藏这些细节的可移植层会从根本上与高性能的目标相悖。

失败提案的历史

C++ 标准中对 SIMD 的推动并非单一的努力,而是一系列尝试。早在 2011 年的提案就基于最终演变成 Eve 等库的概念,但由于与今天相同的理由被委员会拒绝了:难以映射到像 ARM 的 SVE 这样的架构,以及在向量操作中表达控制流的困难。

甚至有一段时间,委员会考虑过将类似 ISPC 的语义——一种用于 SIMD 编程的独立语言——直接集成到 C++ 中。然而,那条路径被放弃了,转而采用了目前的基于库的方法。这表明了一种模式,即委员会试图通过添加满足理论上对可移植性需求的功能来维持“现代”形象,而不是解决向量化的根本架构挑战。

std::simd 是为谁准备的?

这引出了一个关键问题:std::simd 的目标受众是谁?

  • 高性能专家: 很可能会继续使用 intrinsics,因为可移植层会引入不可接受的性能惩罚,且映射的准确性不足以获得最佳结果。

  • 普通用户: 目前因为 intrinsics 太难或令人望而生畏而不用 SIMD 的开发者,可能不会仅仅因为这是一个库而就突然倾向于采用 std::simd

最终,关于 std::simd 的 debate 凸显了 C++ 中的一个根本冲突:在标准库的可移植性与“零开销

Sources