C++ 特征::矢量3f对准

C++ 特征::矢量3f对准,c++,eigen,simd,point-clouds,eigen3,C++,Eigen,Simd,Point Clouds,Eigen3,我使用Eigen来处理非结构化点集(点云),表示为Eigen::Vector3f对象数组。为了启用SIMD矢量化,我将Vector3f子类化为一个带有alignas(16)的类。数组中的每个对象从16字节边界开始,彼此之间有4个字节的间隙,并且包含未初始化的数据 子类目前看起来是这样的:(仍然需要添加模板副本构造函数和操作符=,如Eigen文档中所示) 汇编输出显示正在使用SIMD指令,并且对数组中的每个点_xyz应用转换的a程序似乎工作正常 这样使用Eigen安全吗,还是结果取决于未使用的4字

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

子类目前看起来是这样的:(仍然需要添加模板副本构造函数和操作符
=
,如Eigen文档中所示)

汇编输出显示正在使用SIMD指令,并且对数组中的每个
点_xyz
应用转换的a程序似乎工作正常

这样使用Eigen安全吗,还是结果取决于未使用的4字节间隙的内容,等等

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

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

它产生相同的输出,有和没有
#define EIGEN_DONT_VECTORIZE 1
。使用
Vector4f
,当未禁用Eigen的矢量化时,会生成略短的输出,但这两种输出都在xmm寄存器上运行

AlignedVector3
似乎不支持与
Eigen::Transform
相乘。我在点集上做仿射变换,用3(非同伦)坐标表示。我不确定Eigen是如何通过
Eigen::Vector4f
vector的
Eigen::Transform
实现转换的。即,它是否只改变向量的前3个分量,第四个分量是否必须为零,或者它是否可以包含任意值,或者它是否将4个向量解释为同质坐标?它是否依赖于转换的内部表示(
Affine
AffineCompact
Projective
)。

不要这样做! 改用。 例如:

#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.
#包括
// ...
//并在代码中的某个地方使用它:
本征::对齐矢量3 a,b;
// ...
a+=b;//将使用simd指令,即使知道它们不是真正的3d向量。
该类的工作方式是在不使用最新系数的情况下,在内部存储4d向量(通过特征规则对齐)

该类使其对用户透明。像使用普通3d向量一样使用它,就这么简单


问题中的asm没有使用SIMD,只是矢量寄存器中的标量FP操作,就像x86-64的普通操作一样。(当SSE可用时,适用于x86-32)
addss
是一个FP-add标量单精度。(
addps
是添加打包单)

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


每个16B数据块中的未初始化元素大多会阻止SIMD浮点运算,因为它们可能包含非规范或NAN,使数学指令的速度降低一个数量级以上(除非启用“非规范为零”和“刷新为零”,并且编译器知道这一点并可以利用它)。整数指令在某些元素中没有垃圾性能问题的弱点,但即使有垃圾,也不要期望编译器自动矢量化。

我对使用SIMD感到惊讶。可以肯定的是,在这种情况下,Eigen并没有显式生成SIMD。检查不支持的/Eigen/ALIGNEEDVECTOR3模块,查看显式矢量化的矢量3F。代码似乎效率低下。当然,将使用“SIMD”,因为大多数编译器的fp操作默认使用SSE(即80x87代码不再容易生成)。
mulss
=mul标量单精度。它使用向量寄存器,但不是SIMD。这就是amd64做数学的方式;x87在所有方面都是过时的,除了80位
长双精度
(这比获得超过64位浮点值的任何其他方法都快得多)。虽然这可能回答了这个问题,但在这里包括答案的基本部分,并提供链接供参考。
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;
# 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
#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.