Eigen :: Vector3f对齐

时间:2014-10-04 11:51:22

标签: c++ eigen simd point-clouds eigen3

我正在使用Eigen来处理非结构化点集(点云),表示为Eigen::Vector3f个对象的数组。为了启用SIMD矢量化,我将Vector3f子类化为带有alignas(16)的类。数组中的对象每个都以16字节边界开始,彼此之间有4个字节的间隙,并包含未初始化的数据。

子类看起来像这样:( Stil需要添加模板复制构造函数和运算符=,如Eigen文档中所示)

struct alignas(16) point_xyz : public Eigen::Vector3f {
    using Eigen::Vector3f::Vector3f;
};

point_xyz cloud[n];

程序集输出显示正在使用SIMD指令,并且对阵列中每个point_xyz应用转换的程序似乎正常工作。

以这种方式使用Eigen是否安全,或者结果取决于未使用的4字节间隙的内容等?

另外,将RGB颜色数据或其他数据放入未使用的4个字节(需要覆盖内存对齐)是否安全?

修改: 在启用优化时,似乎clang ++和g ++都会进行一些矢量化。 如果没有优化(对于clang ++而言低于-O2),两者都会生成对特征库函数的调用,以进行以下矩阵乘法(转换):

using transform_t = Eigen::Transform<float, 3, Eigen::Affine>;
transform_t t = Eigen::AngleAxisf(0.01*M_PI, Eigen::Vector3f::UnitX()) * Eigen::Translation3f(0.1, 0.1, 0.1);
Eigen::Vector3f p(123, 234, 345);
std::cout << p << std::endl;

for(;;) {
  asm("# BEGIN TRANS");
  p = t * p;
  asm("# END TRANS");
}
std::cout << p << std::endl;

(需要for循环和cout,以便优化不会删除乘法或放入常量值。)

在GCC(-O1)中导致

# 50 "src/main.cc" 1
    # BEGIN TRANS
# 0 "" 2
    movss   (%rsp), %xmm4
    movaps  %xmm4, %xmm2
    mulss   64(%rsp), %xmm2
    movss   4(%rsp), %xmm0
    movaps  %xmm0, %xmm1
    mulss   80(%rsp), %xmm1
    addss   %xmm1, %xmm2
    movss   8(%rsp), %xmm3
    movaps  %xmm4, %xmm5
    mulss   68(%rsp), %xmm5
    movaps  %xmm0, %xmm1
    mulss   84(%rsp), %xmm1
    addss   %xmm5, %xmm1
    movaps  %xmm3, %xmm5
    mulss   100(%rsp), %xmm5
    addss   %xmm5, %xmm1
    addss   116(%rsp), %xmm1
    mulss   72(%rsp), %xmm4
    mulss   88(%rsp), %xmm0
    addss   %xmm4, %xmm0
    movaps  %xmm3, %xmm4
    mulss   104(%rsp), %xmm4
    addss   %xmm4, %xmm0
    addss   120(%rsp), %xmm0
    mulss   96(%rsp), %xmm3
    addss   %xmm3, %xmm2
    addss   112(%rsp), %xmm2
    movss   %xmm2, (%rsp)
    movss   %xmm1, 4(%rsp)
    movss   %xmm0, 8(%rsp)
# 52 "src/main.cc" 1
    # END TRANS
# 0 "" 2

使用和不使用#define EIGEN_DONT_VECTORIZE 1会产生相同的输出。使用Vector4f时,如果未禁用Eigen的矢量化,则会生成略短的输出,但两者都在xmm寄存器上运行。

AlignedVector3<float>似乎不支持与Eigen::Transform的乘法。我在使用3个(非均匀)坐标表示的点集上进行仿射变换。我不确定Eigen如何使用Eigen::Transform<float, 3, Eigen::Affine>向量的Eigen::Vector4f来实现转换。即它只改变矢量的前3个分量,第四个分量必须为零,还是包含任意值,还是将4矢量解释为同质坐标?它是否依赖于转换的内部表示(AffineAffineCompactProjective)。

1 个答案:

答案 0 :(得分:2)

不要这样做! 请改用Aligned Vector3 unsupported module。 例如:

#include <unsupported/Eigen/AlignedVector3>
// ...
// and use it somewhere in the code:
Eigen::AlignedVector3<double> a, b;
// ...
a += b;// will use simd instruction, even known they aren't real 3d vectors.

这个类的工作方式是在没有使用最新系数的情况下,在内部存储一个4d向量(由Eigen规则对齐)。

这个类使用户对它透明。像使用普通的3d矢量一样使用它,就像那样简单!

问题中的asm没有使用SIMD ,只是向量寄存器中的标量FP操作,如x86-64的正常情况。 (当SSE可用时,对于x86-32)。 addss是FP add Scalar Single-precision。 (addps是单打包装)。

自动向量化仅在-O3的gcc中启用,而不是-O2,并且仅使用-O1

每个16B块中的未初始化元素主要阻止SIMD浮点,因为它们可能包含非正规或NaN,这会使数学指令的速度降低一个数量级以上(除非启用Denormals Are Zero和Flush to Zero,并且编译器知道这一点,并可以利用它)。整数指令在某些元素中没有垃圾性能问题的这个弱点,但是不要指望编译器自动向量化,即使这样。