使用Eigen::Map映射原始缓冲区时的内存对齐与性能问题
必须关注内存对齐,不然不仅会有明显性能损失,在ARM、AVX指令集的x86这类平台上,甚至可能触发未定义行为(比如程序崩溃)。
你的现有代码的问题
你用的vec_raw_是栈上的静态数组,C++标准里栈数组默认只按基础类型对齐(float是4字节),但Eigen要跑SIMD优化,需要更高的对齐要求——比如AVX要32字节对齐,NEON要16字节对齐。现在你用默认的MapOptions::Unaligned,Eigen会自动禁用对齐内存的SIMD优化,只能用标量或者非对齐的SIMD指令,性能直接打折。
怎么改才能搞定对齐?
方法一:给栈数组加对齐属性
用Eigen提供的EIGEN_ALIGN_TO_BOUNDARY宏,直接给vec_raw_设置最大对齐要求,同时把Map的选项改成Aligned让Eigen启用优化:
template<int size> class TestEigenMapClass { public: TestEigenMapClass(): vec_(vec_raw_,size) { vec_.setZero(); } // 显式指定Aligned选项 Eigen::Map<Eigen::VectorXf, Eigen::Aligned> vec_; private: int size_ = size; // 按Eigen最大对齐要求对齐数组 EIGEN_ALIGN_TO_BOUNDARY(EIGEN_MAX_ALIGN_BYTES) float vec_raw_[size]; };
如果你不想用Eigen的宏,也可以用编译器自带的关键字:GCC用__attribute__((aligned(32))),MSVC用__declspec(align(32)),但用Eigen的宏更跨平台。
方法二:堆内存用Eigen的对齐分配器
如果缓冲区换成堆分配,别用普通的new,用Eigen的aligned_allocator来确保内存对齐:
template<int size> class TestEigenMapClass { public: TestEigenMapClass(): vec_raw_(new float[size]), vec_(vec_raw_.get(), size) { vec_.setZero(); } Eigen::Map<Eigen::VectorXf, Eigen::Aligned> vec_; private: int size_ = size; // 用Eigen的对齐分配器管理堆内存 std::unique_ptr<float, Eigen::aligned_allocator<float>> vec_raw_; };
性能差距到底有多大?
对齐内存下,Eigen能直接用完整的SIMD指令——比如AVX的256位指令,一次能处理8个float;非对齐的话,要么拆分指令,要么直接回退到标量运算,性能差个2到10倍都有可能,看你做的计算复杂程度。而且有些ARM架构上,访问非对齐内存直接触发总线错误,程序直接崩。
怎么确认内存对齐了?
用Eigen自带的工具函数就能查:
bool is_aligned = Eigen::internal::is_aligned(vec_raw_);
返回true就说明内存满足要求,可以放心开Aligned选项。
内容的提问来源于stack exchange,提问作者Ernest

