记录一次崩溃问题排查过程(gtsam库相关,avx)

记录一次崩溃问题排查过程(gtsam库相关)

  • 有同学在使用 gtsam库(4.1.1)的时候,出现了崩溃问题,位置在 Eigen::Quaternion 赋值操作上 operator=
  • 由于堆栈打印信息不全,让他用 debug 模式编译(-g -O0) , 再次测试得到的堆栈信息如下:
bash 复制代码
libMapping3d.so!_mm256_store_pd(__m256d__A, double *__P) (\usr\lib\gcc\x86_64-linux-gnu\9\include\avxintrin.h:868)
libMapping3d.so!Eigen::internal::pstore<double, double__vector(4)>(double*, double __vector(4) const&)(double *to, const Eigen::internal::Packet4d & from) (\usr\include\eigen3\Eigen\src\Core\arch\AVX\PacketMath.h:252)
libMapping3d.so!Eigen::internal::pstoret<double, double__vector(4), 32>(double*, double __vector(4) const&)(const double (&) __attribute__ ((vector_size(4))) from, double *to) (\usr\include\eigen3\Eigen\src\Core\GenericPacketMath.h:474)
libMapping3d.so!Eigen::internal::assign_op<double, double>::assignPacket<32, double__vector(4)>(double*, double __vector(4) const&) const(const Eigen::internal::assign_op<double, double> *const this, double* a, const double (&) __attribute__ ((vector_size(4))) b) (\usr\include\eigen3\Eigen\src\Core\functors\AssignmentFunctors.h:28)
libMapping3d.so!Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>::assignPacket<32, 32, double__vector(4)>(long, long)(Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0> *const this, Eigen::Index row, Eigen::Index col) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:652)
libMapping3d.so!Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>::assignPacketByOuterInner<32, 32, double __vector(4)>(long, long)(Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>* const this, Eigen::Index outer, Eigen::Index inner) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:666)
libMapping3d.so!Eigen::internal::copy_using_evaluator_innervec_CompleteUnrolling<Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>, 0, 4>::run(Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0> & kernel) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:274)
libMapping3d.so!Eigen::internal::dense_assignment_loop<Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0>, 2, 2>::run(Eigen::internal::generic_dense_assignment_kernel<Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::evaluator<Eigen::Matrix<double, 4, 1, 0, 4, 1> >, Eigen::internal::assign_op<double, double>, 0> & kernel) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:468)
libMapping3d.so!Eigen::internal::call_dense_assignment_loop<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::internal::assign_op<double, double> >(Eigen::Matrix<double, 4, 1, 0, 4, 1> & dst, const Eigen::Matrix<double, 4, 1, 0, 4, 1> & src, const Eigen::internal::assign_op<double, double> & func) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:741)
libMapping3d.so!Eigen::internal::Assignment<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::internal::assign_op<double, double>, Eigen::internal::Dense2Dense, void>::run(Eigen::Matrix<double, 4, 1, 0, 4, 1> & dst, const Eigen::Matrix<double, 4, 1, 0, 4, 1> & src, const Eigen::internal::assign_op<double, double> & func) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:879)
libMapping3d.so!Eigen::internal::call_assignment_no_alias<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::internal::assign_op<double, double> >(Eigen::Matrix<double, 4, 1, 0, 4, 1> & dst, const Eigen::Matrix<double, 4, 1, 0, 4, 1> & src, const Eigen::internal::assign_op<double, double> & func) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:836)
libMapping3d.so!Eigen::internal::call_assignment<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::internal::assign_op<double, double> >(Eigen::Matrix<double, 4, 1, 0, 4, 1>&, Eigen::Matrix<double, 4, 1, 0, 4, 1> const&, Eigen::internal::assign_op<double, double> const&, Eigen::internal::enable_if<!Eigen::internal::evaluator_assume_aliasing<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::internal::evaluator_traits<Eigen::Matrix<double, 4, 1, 0, 4, 1> >::Shape>::value, void*>::type)(Eigen::Matrix<double, 4, 1, 0, 4, 1> & dst, const Eigen::Matrix<double, 4, 1, 0, 4, 1> & src, const Eigen::internal::assign_op<double, double> & func) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:804)
libMapping3d.so!Eigen::internal::call_assignment<Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, 4, 1, 0, 4, 1> >(Eigen::Matrix<double, 4, 1, 0, 4, 1> & dst, const Eigen::Matrix<double, 4, 1, 0, 4, 1> & src) (\usr\include\eigen3\Eigen\src\Core\AssignEvaluator.h:782)
libMapping3d.so!Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >::_set<Eigen::Matrix<double, 4, 1, 0, 4, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >* const this, const Eigen::DenseBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> > & other) (\usr\include\eigen3\Eigen\src\Core\PlainObjectBase.h:714)
libMapping3d.so!Eigen::Matrix<double, 4, 1, 0, 4, 1>::operator=(Eigen::Matrix<double, 4, 1, 0, 4, 1> *const this, const Eigen::Matrix<double, 4, 1, 0, 4, 1> & other) (\usr\include\eigen3\Eigen\src\Core\Matrix.h:208)
libMapping3d.so!Eigen::QuaternionBase<Eigen::Quaternion<double, 0> >::operator=(Eigen::QuaternionBase<Eigen::Quaternion<double, 0> >* const this, const Eigen::QuaternionBase<Eigen::Quaternion<double, 0> > & other) (\usr\include\eigen3\Eigen\src\Geometry\Quaternion.h:493)
libMapping3d.so!Eigen::Quaternion<double, 0>::operator=(Eigen::Quaternion<double, 0> *const this, const Eigen::Quaternion<double, 0> & other) (\usr\include\eigen3\Eigen\src\Geometry\Quaternion.h:243)
libMapping3d.so!ModelParam::operator=(ModelParam* const this) (\home\source\dataprocess\Mapping3d\internal_include\common\data_process.h:78)
libMapping3d.so!Mapping3DParam::operator=(Mapping3DParam *const this) (\home\source\dataprocess\Mapping3d\internal_include\common\data_process.h:323)
libMapping3d.so!mapping3d::Mapping3DAlg::init(mapping3d::Mapping3DAlg* const this, const Mapping3DParam & param)
......
  • 看着挺多的,实际关键的信息有一下两点:

    • 一是 Eigen::Quaternion<double, 0>::operator=,确定是 eigen 四元数类赋值报错
    • 二是 _mm256_store_pd(__m256d__A, double *__P) (\usr\lib\gcc\x86_64-linux-gnu\9\include\avxintrin.h:868)
      • 这个是 底层 AVX 指令:将 256 位向量寄存器中的数据,存储到内存地址__P 。AVX 是 x86_64 架构的 SIMD 指令集,用于向量运算加速(如矩阵 / 四元数计算)。
  • 系统中安装的eigen库,一般来说是没开加速优化的,于是排查发现 gtsam库 源码居然包了一个 eigen库 ,在 gtsam/3rdparty/Eigen 目录 ;

  • 实际程序运行的时候是用的这个 eigen库(开了加速优化)。

  • 解决方案有两个:

    • 一是 按规范进行 字节对齐
    • 二是 重新编译gtsam库,使用系统 eigen库 (未开加速优化)

方案一 :按规范进行 字节对齐

  • 字节对齐写法如下:
c++ 复制代码
#include <Eigen/Core>
#include <Eigen/Geometry>

// 1. 用 __attribute__((aligned(32))) 强制结构体整体 32 bit对齐(GCC 专用)
// 2. 重载 new 运算符,确保堆上分配时对齐(Eigen 提供的宏)
struct __attribute__((aligned(32))) ModelParam {
    // Eigen 成员:需放在结构体前部(减少内存碎片,确保对齐)
    Eigen::Quaterniond rotation;  // 四元数(8 bit * 4 = 32 bit,需 32 bit对齐)
    Eigen::Vector4d translation;  // 4 维平移向量(8 bit * 4 = 32 bit)

    // 
    double scale;

    // 关键:Eigen 提供的宏,重载 new/delete,确保堆上分配时 32 bit对齐
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    // 自定义赋值运算符(若需手动实现,需确保 Eigen 成员正确赋值)
    ModelParam& operator=(const ModelParam& other) {
        if (this != &other) {
            rotation = other.rotation;    // Eigen 成员自动处理对齐赋值
            translation = other.translation;
            scale = other.scale;
        }
        return *this;
    }

};


// 用重载后的 new  分配对象内存
ModelParam* param_ptr1 = new ModelParam();  // 自动 32 bit对齐
  • 这样 修改后 就可以正常运行了,但是由于他应该是 找的一个开源算法库,里面涉及用到 Eigen 的类 较多,修改起来不方便;

方案二:重新编译gtsam库,使用系统 eigen库

  • 使用的docker容器 系统环境是 ubuntu22.04 , boost_1.71.0 , eigen_3.4.0 , gcc-11, cmake_3.30.2

  • 满足 gtsam 的编译要求.

  • 下载 gtsam 库:

bash 复制代码
git clone https://github.com/borglab/gtsam.git 
git checkout 4.1.1
  • 大概研究了下 gtsam 库 cmake 文件结构,发现里面配置不少,我就不需要的都关了,并配置使用系统 eigen 库,最终的编译脚本如下:
bash 复制代码
mkdir -p build && cd build 

cmake .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DGTSAM_USE_SYSTEM_EIGEN=ON \
    -DGTSAM_BUILD_UNSTABLE=OFF \
    -DGTSAM_BUILD_PYTHON=OFF \
    -DGTSAM_WITH_TBB=OFF \
    -DGTSAM_WITH_EIGEN_MKL=OFF \
    -DGTSAM_WITH_EIGEN_MKL_OPENMP=OFF \
    -DGTSAM_BUILD_EXAMPLES_ALWAYS=OFF \
    -DGTSAM_BUILD_TESTS=OFF \
    -DGTSAM_BUILD_TIMING_ALWAYS=OFF \
    -DCMAKE_INSTALL_PREFIX=/opt/tong/prefix/install

make -j4
make install
  1. -DCMAKE_BUILD_TYPE=Release : 设置构建类型为 Release
  2. -DGTSAM_USE_SYSTEM_EIGEN=ON :使用系统上已安装的 Eigen 库 。
  3. -DGTSAM_BUILD_UNSTABLE=OFF :关闭构建 GTSAM 中标记为 (unstable) 的功能或模块。
  4. -DGTSAM_BUILD_PYTHON=OFF : 关闭构建 GTSAM 的 Python 接口(封装)。
  5. -DGTSAM_WITH_TBB=OFF : 关闭 Intel Threading Building Blocks (TBB) 支持。
  6. -DGTSAM_WITH_EIGEN_MKL=OFF : 关闭使用 Intel Math Kernel Library (MKL) 来加速 Eigen 库的计算。
  7. -DGTSAM_WITH_EIGEN_MKL_OPENMP=OFF : 关闭使用 MKL 的 OpenMP 后端来加速 Eigen。
  8. -DGTSAM_BUILD_EXAMPLES_ALWAYS=OFF : 关闭构建示例程序
  9. -DGTSAM_BUILD_TESTS=OFF :关闭构建 GTSAM 的单元测试和测试程序。(验证库的功能是否正确可以打开,但在部署安装时通常不需要)
  10. -DCMAKE_INSTALL_PREFIX=/opt/tong/prefix/install : 设置安装目录。
  • 以上构建一个精简、优化、不包含额外功能 的 GTSAM 发布版本 (使用系统Eigen库,并禁用了并行计算库的支持(TBB/MKL))。
  • 使用以上编译好的库替换原来gtsam库就可以正常运行了。
  • 如果想用计算加速库,必须遵循其对应的规则和要求。
  • 编出来库 结构如下:
bash 复制代码
root@ac41c3b78c6c:/opt/tong/prefix/install# tree -L 2
.
|-- include
|   |-- CppUnitLite
|   `-- gtsam
`-- lib
    |-- cmake
    |-- libCppUnitLite.a
    |-- libgtsam.so -> libgtsam.so.4
    |-- libgtsam.so.4 -> libgtsam.so.4.1.1
    |-- libgtsam.so.4.1.1
    `-- libmetis-gtsam.so
  • 查看库的依赖:
bash 复制代码
root@ac41c3b78c6c:/opt/tong/prefix/install# ldd lib/libgtsam.so
        linux-vdso.so.1 (0x00007fffc3dc7000)
        libboost_serialization.so.1.71.0 => /usr/local/lib/libboost_serialization.so.1.71.0 (0x00007f0e2dd9c000)
        libboost_filesystem.so.1.71.0 => /usr/local/lib/libboost_filesystem.so.1.71.0 (0x00007f0e2dd7d000)
        libboost_timer.so.1.71.0 => /usr/local/lib/libboost_timer.so.1.71.0 (0x00007f0e2dd72000)
        libmetis-gtsam.so => not found
        libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f0e2db46000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0e2da5d000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f0e2da3d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e2d814000)
        libboost_chrono.so.1.71.0 => /usr/local/lib/libboost_chrono.so.1.71.0 (0x00007f0e2d807000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f0e2e39f000)
root@ac41c3b78c6c:/opt/tong/prefix/install# ldd lib/libmetis-gtsam.so 
        linux-vdso.so.1 (0x00007ffe5a122000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007efc926a6000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007efc9247d000)
        /lib64/ld-linux-x86-64.so.2 (0x00007efc92825000)
  • eigen 相关函数已经编译进去了,运行时只需再依赖 boost 库就可以。
  • 这样库就可以打包(deb)使用了,要注意的是cmake里面路径可能需要修改(如果库位置发生变化)。

总结

  • 主要原因还是引入了外部库,且对其使用不熟悉。
  • 遇到了 崩溃问题,先把其 详细堆栈信息(debug)保存下来,以供分析。
  • 在使用外部库时,需要明确其依赖关系,确保不与其他库冲突。
相关推荐
AAA小肥杨4 小时前
cmake使用教程
c语言·c++·cmake
zh_xuan5 小时前
c++ stringstream字符串流的用法
开发语言·c++
love530love5 小时前
【笔记】解决 ComfyUI 安装节点 ComfyUI-Addoor (葵花宝典)后启动报错:No module named ‘ComfyUI-Addoor’
linux·运维·前端·人工智能·windows·笔记·python
小老鼠不吃猫5 小时前
C++ STL <algorithm>中泛型算法:查找、排序、修改、统计、生成
c++·算法·排序算法
Full Stack Developme5 小时前
Linux 有哪些功能相似的命令
linux·运维·服务器
馨谙5 小时前
Linux 服务管理:重新加载 vs 重新启动的本质区别
linux·运维·服务器
小白银子6 小时前
零基础从头教学Linux(Day 55)
java·linux·服务器·python
GOATLong6 小时前
MySQL内置函数
android·数据库·c++·vscode·mysql
岚天start6 小时前
Linux内核coredump分析方案
linux·运维·服务器·gdb·coredump·堆栈·内存快照