You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Eigen::VectorXd的operator+=比std::vector循环相加慢约69%?

以下代码需依赖google benchmark,实现填充两个向量并执行相加操作,结果存储在第一个向量中。我分别使用Eigen::VectorXd和std::vector作为向量类型进行性能对比:

#include <Eigen/Core>
#include <benchmark/benchmark.h>
#include <vector>

auto constexpr N = 1024u;

template <typename TVector>
TVector generate(unsigned min) {
    TVector v(N);
    for (unsigned i = 0; i < N; ++i)
        v[i] = static_cast<double>(min + i);
    return v;
}

auto ev1 = generate<Eigen::VectorXd>(0);
auto ev2 = generate<Eigen::VectorXd>(N);
auto sv1 = generate<std::vector<double>>(0);
auto sv2 = generate<std::vector<double>>(N);

void add_vectors(Eigen::VectorXd& v1, Eigen::VectorXd const& v2) {
    v1 += v2;
}

void add_vectors(std::vector<double>& v1, std::vector<double> const& v2) {
    for (unsigned i = 0; i < N; ++i)
        v1[i] += v2[i];
}

static void eigen(benchmark::State& state) {
    for (auto _ : state) {
        add_vectors(ev1, ev2);
        benchmark::DoNotOptimize(ev1);
    }
}

static void standard(benchmark::State& state) {
    for (auto _ : state) {
        add_vectors(sv1, sv2);
        benchmark::DoNotOptimize(sv1);
    }
}

BENCHMARK(standard);
BENCHMARK(eigen);

测试运行在Intel Xeon E-2286M @2.40Ghz处理器上,使用Eigen 3.3.9版本、MSVC 16.11.2编译器,启用的相关编译选项包括/GL、/Gy、/O2、/D "NDEBUG"、/Oi、/arch:AVX,典型的运行输出如下:

Run on (16 X 2400 MHz CPU s)
CPU Caches:
  L1 Data 32K (x8)
  L1 Instruction 32K (x8)
  L2 Unified 262K (x8)
  L3 Unified 16777K (x1)
--------------------------------------------------
Benchmark           Time           CPU Iterations
--------------------------------------------------
standard           99 ns        100 ns    7466667
eigen             169 ns        169 ns    4072727

结果显示std::vector的相加操作比Eigen::VectorXd快约69%。二者的核心循环汇编代码如下:

// For Eigen::VectorXd
00007FF672221A11  vmovupd     ymm0,ymmword ptr [rcx+rax*8]  
00007FF672221A16  vaddpd      ymm1,ymm0,ymmword ptr [r8+rax*8]  
00007FF672221A1C  vmovupd     ymmword ptr [r8+rax*8],ymm1  
00007FF672221A22  add         rax,4  
00007FF672221A26  cmp         rax,rdx  
00007FF672221A29  jge         eigen+0C7h (07FF672221A37h)  
00007FF672221A2B  mov         rcx,qword ptr [rsp+48h]  
00007FF672221A30  mov         r8,qword ptr [rsp+58h]  
00007FF672221A35  jmp         eigen+0A1h (07FF672221A11h)  

// For std::vector
00007FF672221B40  vmovups     ymm1,ymmword ptr [rax+rdx-20h]  
00007FF672221B46  vaddpd      ymm1,ymm1,ymmword ptr [rax+rcx-20h]  
00007FF672221B4C  vmovups     ymmword ptr [rax+rcx-20h],ymm1  
00007FF672221B52  vmovups     ymm1,ymmword ptr [rax+rdx]  
00007FF672221B57  vaddpd      ymm1,ymm1,ymmword ptr [rax+rcx]  
00007FF672221B5C  vmovups     ymmword ptr [rax+rcx],ymm1  
00007FF672221B61  lea         rax,[rax+40h]  
00007FF672221B65  sub         r8,1  
00007FF672221B69  jne         standard+0C0h (07FF672221B40h)  

可以看到二者均使用vaddpd指令一次完成4个double类型数值的相加,但std::vector对应的循环被编译器展开,每次迭代执行2次vaddpd,而Eigen对应的循环没有被展开;另一个潜在差异是std::vector的循环地址按32字节对齐。

我添加/Qvec-report:2编译选项后得到如下提示:

[...]\Core\AssignEvaluator.h(415) : info C5002: loop not vectorized due to reason '1305'

查阅微软官方文档可知,错误码1305的含义是“类型信息不足”。我猜测是Eigen内部手动使用_mm256_add_pd等内建函数的优化逻辑干扰了编译器,反而影响了性能,直接让编译器做自动向量化效果更好。请问我是否有遗漏的优化点?该问题是否属于Eigen的优化缺失bug?


问题解答

遗漏的优化点

你确实有几个Eigen相关的优化配置没有启用:

  • 开启内存对齐定义:添加编译参数/D EIGEN_MAX_ALIGN_BYTES=32,保证Eigen的堆分配内存按AVX要求的32字节对齐,优化后Eigen的内存访问指令可以从非对齐的vmovupd换成对齐的vmovapd,降低内存访问开销。
  • 按需禁用Eigen内置向量化:添加编译参数/D EIGEN_DONT_VECTORIZE,关闭Eigen内部手写的SIMD实现,完全交给MSVC做自动向量化和循环展开,在你这个简单的向量加法场景下,编译器的激进优化效果会优于Eigen的跨平台通用SIMD实现。
  • 适配固定长度场景:你的测试用例使用固定长度1024的向量,可以把Eigen::VectorXd换成固定大小的Eigen::Matrix<double, 1024, 1>,编译器可以获取完整的长度信息,做更极致的循环展开优化。

是否属于Eigen的优化bug

该结果不属于Eigen的优化缺失bug:

  • Eigen的核心设计目标是覆盖通用矩阵运算场景,尤其是大尺寸矩阵、多操作链式运算的场景,手写SIMD逻辑的核心作用是保证跨GCC、Clang、MSVC等不同编译器的性能下限,针对你这种单一的小尺寸向量加法的极端场景,限制了特定编译器的激进优化空间属于设计取舍,不是缺陷。
  • 你使用的MSVC 2019版本自动向量化能力已经有较大提升,简单单层循环的自动优化效果超过Eigen的通用SIMD实现属于正常现象,相同代码在GCC或Clang下测试,大概率会出现Eigen性能反超的结果。
  • Eigen 3.4及以上版本已经优化了对MSVC编译器的向量化适配,升级版本后重新测试,二者的性能差距会大幅缩小。

内容的提问来源于stack exchange,提问作者Cassio Neri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 21:09:03