c++ - 使用 Eigen 和 std::vector 的 SIGSEGV

标签 c++ c++11 vectorization eigen memory-alignment

我知道将 Eigen 的类型与动态内存结合使用时会出现对齐问题。因此,我决定使用 Eigen::DontAlign in accord with this page 禁用矢量化,但以下代码仍然会在执行时持续引发 SIGSEGV。如果有人能阐明为什么会发生这种情况,我将非常高兴。在我看来,使用 Eigen::DontAlign 应该可以让我摆脱错综复杂的对齐问题。

#include <Eigen/Dense>
#include <vector>

int main()
{
    using vec_t = Eigen::Matrix< double, 4, 1, Eigen::DontAlign >;
    std::vector< vec_t > foo;
    foo.emplace_back( 0.0, 0.0, 0.0, 1.0 );
    vec_t vec{ -4.0, 1.0, 3.0, 1.0 };
    foo.push_back( vec );
}

GDB 输出:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000408bed in Eigen::internal::evaluator<Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 2, 4, 1> > >::packet<0, double __vector(4)>(long long, long long) const (this=0x22fa90, row=0, col=0)
    at C:/Dev/Eigen/Eigen/src/Core/CoreEvaluators.h:197
197           return ploadt<PacketType, LoadMode>(m_data + row + col * m_outerStride.value());
(gdb) l
192       PacketType packet(Index row, Index col) const
193       {
194         if (IsRowMajor)
195           return ploadt<PacketType, LoadMode>(m_data + row * m_outerStride.value() + col);
196         else
197           return ploadt<PacketType, LoadMode>(m_data + row + col * m_outerStride.value());
198       }
199
200       template<int LoadMode, typename PacketType>
201       EIGEN_STRONG_INLINE
(gdb) bt
#0  0x0000000000408bed in Eigen::internal::evaluator<Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 2, 4, 1> > >::packet<0, double __vector(4)>(long long, long long) const (this=0x22fa90, row=0, col=0) at C:/Dev/Eigen/Eigen/src/Core/CoreEvaluators.h:197
#1  0x000000000040678a in Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>::assignPacket<0, 0, double __vector(4)>(long long, long long) (this=0x22fa60, row=0, col=0) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:652
#2  0x0000000000406863 in Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>::assignPacketByOuterInner<0, 0, double __vector(4)>(long long, long long) (this=0x22fa60, outer=0, inner=0) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:666
#3  0x00000000004068e0 in Eigen::internal::copy_using_evaluator_innervec_CompleteUnrolling<Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>, 0, 4>::run (kernel=...) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:274
#4  0x00000000004064d5 in Eigen::internal::dense_assignment_loop<Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 2, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>, 2, 2>::run (kernel=...) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:468
#5  0x0000000000406693 in Eigen::internal::call_dense_assignment_loop<Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::internal::assign_op<double, double> > (dst=..., src=..., func=...) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:724
#6  0x00000000004062ab in Eigen::internal::Assignment<Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::internal::assign_op<double, double>, Eigen::internal::Dense2Dense, void>::run (dst=..., src=..., func=...) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:862
#7  0x00000000004065a3 in Eigen::internal::call_assignment_no_alias<Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::internal::assign_op<double, double> > (dst=..., src=..., func=...) at C:/Dev/Eigen/Eigen/src/Core/AssignEvaluator.h:819
#8  0x0000000000405bdc in Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 2, 4, 1> >::_set_noalias<Eigen::Matrix<double, 4, 1, 2, 4, 1> > (this=0x3c2680, other=...) at C:/Dev/Eigen/Eigen/src/Core/PlainObjectBase.h:728
#9  0x0000000000406070 in Eigen::Matrix<double, 4, 1, 2, 4, 1>::Matrix(Eigen::Matrix<double, 4, 1, 2, 4, 1>&&) (this=0x3c2680, other=<unknown type in F:\GitHub\Radon\bin\Radon.exe, CU 0x0, DIE 0x1faef>) at C:/Dev/Eigen/Eigen/src/Core/Matrix.h:278
#10 0x000000000040c666 in std::_Construct<Eigen::Matrix<double, 4, 1, 2, 4, 1>, Eigen::Matrix<double, 4, 1, 2, 4, 1> >(Eigen::Matrix<double, 4, 1, 2, 4, 1>*, Eigen::Matrix<double, 4, 1, 2, 4, 1>&&) (__p=0x3c2680, __args#0=<unknown type in F:\GitHub\Radon\bin\Radon.exe, CU 0x0, DIE 0x1faef>) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/stl_construct.h:75
#11 0x000000000040ad69 in std::__uninitialized_copy<false>::__uninit_copy<std::move_iterator<Eigen::Matrix<double, 4, 1, 2, 4, 1>*>, Eigen::Matrix<double, 4, 1, 2, 4, 1>*> (__first=..., __last=..., __result=0x3c2680) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/stl_uninitialized.h:75
#12 0x000000000040c8bf in std::uninitialized_copy<std::move_iterator<Eigen::Matrix<double, 4, 1, 2, 4, 1>*>, Eigen::Matrix<double, 4, 1, 2, 4, 1>*> (__first=..., __last=..., __result=0x3c2680) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/stl_uninitialized.h:126
#13 0x000000000040c9ff in std::__uninitialized_copy_a<std::move_iterator<Eigen::Matrix<double, 4, 1, 2, 4, 1>*>, Eigen::Matrix<double, 4, 1, 2, 4, 1>*, Eigen::Matrix<double, 4, 1, 2, 4, 1> > (__first=..., __last=..., __result=0x3c2680) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/stl_uninitialized.h:281
#14 0x000000000040ccaf in std::__uninitialized_move_if_noexcept_a<Eigen::Matrix<double, 4, 1, 2, 4, 1>*, Eigen::Matrix<double, 4, 1, 2, 4, 1>*, std::allocator<Eigen::Matrix<double, 4, 1, 2, 4, 1> > > (__first=0x3c2980, __last=0x3c29a0, __result=0x3c2680, __alloc=...) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/stl_uninitialized.h:304
#15 0x000000000040b648 in std::vector<Eigen::Matrix<double, 4, 1, 2, 4, 1>, std::allocator<Eigen::Matrix<double, 4, 1, 2, 4, 1> > >::_M_emplace_back_aux<Eigen::Matrix<double, 4, 1, 2, 4, 1> const&> (this=0x22fde0, __args#0=...) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/vector.tcc:420
#16 0x000000000040ba16 in std::vector<Eigen::Matrix<double, 4, 1, 2, 4, 1>, std::allocator<Eigen::Matrix<double, 4, 1, 2, 4, 1> > >::push_back (this=0x22fde0, __x=...) at C:/Dev/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev1/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/stl_vector.h:924
#17 0x000000000040167f in main () at F:\GitHub\Radon\Radon.cxx:10
(gdb)

环境:Windows 7 64 位 SP1

硬件:i7-6800k(支持 AVX2)

编译器:MinGW-w64 (x86_64-6.3.0-posix-seh-rt_v5-rev1)

标记 -Wall -Wextra -pedantic-errors -Wno-deprecated -std=c++14 -march=native -g -ggdb -fno-omit-frame-pointer

Eigen 版本:3.3.2

最佳答案

本身没有解决方案,但对发生的事情有更多的了解。首先,我也可以在 MinGW 上使用 gcc 5.3.0 进行重现,所以不仅仅是你。其次,通过运行 gcc -march=native -Q --help=target ... | grep enabled 我在(不同的)设置(我使用的是较旧的 i5 等)中获得了 -march=native 启用的标志列表。我以二进制方式对它们进行了划分,直到我想出了在 MCVE (+1) 的修改版本中触发相同错误所需的两个标志列表(在我的例子中):

#include <Eigen/Core>
#include <Eigen/StdVector>
#include <iostream>
#include <vector>

using vec_t = Eigen::Matrix< double, 4, 1, Eigen::DontAlign >;
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(vec_t)

int main()
{
    //  , Eigen::aligned_allocator<vec_t> 
    std::vector< vec_t> foo;
    std::cout << "Before emplace_back\n";
    foo.emplace_back( 0.0, 0.0, 0.0, 1.0 );
    std::cout << "Before vec\n";
    vec_t vec{ -4.0, 1.0, 3.0, 1.0 };
    std::cout << "Before push_back\n";
    foo.push_back( vec );
    std::cout << "After push_back\n";
    return 0;
}

它们是 -mavx-mf16c,两个启用 AVX 指令的标志。 gdb 输出略有不同,因为我确实使用了指令 here :

Program received signal SIGSEGV, Segmentation fault. 0x0000000000403ca4 in Eigen::internal::ploadu(Eigen::internal::unpacket_traits::type const*) ( from=0x312340) at C:/include/Eigen3.3.2/Eigen/src/Core/arch/AVX/PacketMath.h:218 218 template<> EIGEN_STRONG_INLINE Packet4d ploadu(const double* from) { EIGEN_DEBUG_UNALIGNED_LOAD return _mm256_loadu_pd(from); }

所以我们看到 Eigen 仍然使用未对齐的负载使用 AVX 进行矢量化,因为我们只告诉 Eigen 不要对齐并且我们没有在预处理器中指定 -DEIGEN_DONT_VECTORIZE(或作为 #define 在包含 Eigen 之前)。添加它可以删除段错误。因此,解决方法是禁用矢量化(甚至未对齐)。如果这足够了,那就太好了。如果没有,请等待 ggael & co。 (或其他人)找出更好的解决方案。

关于c++ - 使用 Eigen 和 std::vector 的 SIGSEGV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42181586/

相关文章:

c++ - boost 正则表达式捕获组

c++ - 如何使用 "priority"进行多线程处理?

c++ - 与函数中的返回值不同的数据类型?

c++ - 如何让编译器更喜欢 C++ 中的 const 方法重载?

c++ - 缩小 unsigned int 到 short unsigned int 的转换

c++11 - ip::tcp::socket.close() 线程安全吗?

c++ - 是否可以将文字值传递给 C++ 中的 lambda 一元谓词?

machine-learning - 使用词向量进行文档分类

algorithm - 从 MATLAB 中的聚类算法中删除 for 循环

python - 如何对所有网格进行矢量化计算而不是 'for' 循环?