C++ Python 模块在 Blender 中崩溃,但在 Python 控制台中没有
Posted
技术标签:
【中文标题】C++ Python 模块在 Blender 中崩溃,但在 Python 控制台中没有【英文标题】:C++ Python module crashes in Blender but not in Python console 【发布时间】:2020-10-09 17:27:53 【问题描述】:问题
我正在尝试使用 Blender 2.82a 从 Python 3.7 调用我的 C++ 代码(也发生在 2.83 中)。该代码应优化相机路径。它可以在没有 Blender 的情况下使用,但是,我使用 Blender 设置具有相机路径的场景并查询场景中的深度值。
我尝试在 C++ 和 Python 控制台中调用优化函数。两者都没有任何问题。问题是,当我在 Blender 中调用它时,Blender 崩溃了。
这是崩溃报告:
# Blender 2.83.0, Commit date: 2020-06-03 14:38, Hash 211b6c29f771
# backtrace
./blender(BLI_system_backtrace+0x1d) [0x6989e9d]
./blender() [0xc1548f]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x153c0) [0x7fa5fb3dc3c0]
/lib/x86_64-linux-gnu/libpthread.so.0(raise+0xcb) [0x7fa5fb3dc24b]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x153c0) [0x7fa5fb3dc3c0]
./blender(_ZN5Eigen8IOFormatD1Ev+0xa3) [0x179bc43]
/home/name/Programs/blender-2.83.0-linux64/2.83/python/lib/python3.7/optFlowCam.cpython-37m-x86_64-linux-gnu.so(_Z2_zRK6CameraRKN5Eigen6MatrixIdLi9ELi1ELi0ELi9ELi1EEEiiRKSt8functionIFdRK3RayEE+0x2e2) [0x7fa5d1538e72]
/home/name/Programs/blender-2.83.0-linux64/2.83/python/lib/python3.7/optFlowCam.cpython-37m-x86_64-linux-gnu.so(_ZN11OpticalFlow13GradPathErrorERKSt6vectorI6CameraSaIS1_EEiiRKSt8functionIFdRK3RayEEd+0x5a7) [0x7fa5d1539c77]
/home/name/Programs/blender-2.83.0-linux64/2.83/python/lib/python3.7/optFlowCam.cpython-37m-x86_64-linux-gnu.so(_Z16_gradientDescentRKSt6vectorI6CameraSaIS0_EEiiRKSt8functionIFdRK3RayEEd+0x54b) [0x7fa5d153b5fb]
/home/name/Programs/blender-2.83.0-linux64/2.83/python/lib/python3.7/optFlowCam.cpython-37m-x86_64-linux-gnu.so(_ZN11OpticalFlow12OptimizePathERKSt6vectorI6CameraSaIS1_EEiiRKSt8functionIFdRK3RayEEdNS_18OptimizationMethodE+0x22) [0x7fa5d153bcb2]
/home/name/Programs/blender-2.83.0-linux64/2.83/python/lib/python3.7/optFlowCam.cpython-37m-x86_64-linux-gnu.so(+0x3d910) [0x7fa5d1533910]
/home/name/Programs/blender-2.83.0-linux64/2.83/python/lib/python3.7/optFlowCam.cpython-37m-x86_64-linux-gnu.so(+0x317ed) [0x7fa5d15277ed]
./blender(_PyMethodDef_RawFastCallKeywords+0x2f3) [0x570f373]
./blender(_PyCFunction_FastCallKeywords+0x25) [0x570f3f5]
./blender(_PyEval_EvalFrameDefault+0x7468) [0xc0fb48]
./blender(_PyEval_EvalCodeWithName+0xadc) [0x57c0d8c]
./blender(PyEval_EvalCodeEx+0x3e) [0x57c0ebe]
./blender(PyEval_EvalCode+0x1b) [0x57c0eeb]
./blender() [0x11f35ac]
./blender() [0x1600cde]
./blender() [0xec6a93]
./blender() [0xec6d07]
./blender(WM_operator_name_call_ptr+0x1a) [0xec720a]
./blender() [0x14f2082]
./blender() [0x15020d5]
./blender() [0xeca877]
./blender() [0xecaecc]
./blender(wm_event_do_handlers+0x310) [0xecb5e0]
./blender(WM_main+0x20) [0xec2230]
./blender(main+0x321) [0xb4bfd1]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7fa5facb50b3]
./blender() [0xc11c0c]
我使用 Eigen 进行线性代数计算,并使用 pybind11 将其编译成 python 模块。 Eigen 类型都是固定大小的,因为我不需要它们是动态的(问题的可能原因)。我在 Ubuntu 20.04 上使用 gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
编译。我目前使用 c++11 标准,但这不是必需的。
目前的调查结果
使用 faulthandler.enabled() 它给了我
Fatal Python error: Segmentation fault
Current thread 0x00007fa5fab18040 (most recent call first):
File "/Text", line 16 in <module>
我已经发现它在程序中在同一行崩溃,这是应该返回矩阵向量乘法的结果并将其插入到 std::vector 中的时候。我事先打印了向量和矩阵,以确保它们不包含垃圾并且工作正常。
我还尝试将它存储在一个中间变量中并打印它,然后它在打印时崩溃。 乘法本身似乎不会导致段错误。
我想,我尝试直接从 Blender 调用该函数发生的位置,但随后它可以工作并返回没有段错误的结果。
我怀疑这是某种内存对齐问题,并尝试了here 和 Eigen 纪录片中建议的所有方法。即,我在每个 std::vector 中使用 Eigen::aligned_allocator
,仅将 Eigen 对象作为 const &
传递,并且在具有 Eigen 类型成员的相机和光线类中具有 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
。
使用#define EIGEN_DONT_VECTORIZE
和#define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
只给了我部分成功。它不会再像以前那样在同一行崩溃了。奇怪的是,如果我还在返回之前添加了一个 cout,那么函数就会完成并返回。
发生崩溃的部分:
这个项目是不公开的,C++代码很长,所以我只包括它的一部分。如果您需要更多,请告诉我。其余的看起来非常相似,所以如果有什么概念上的错误,这里也可能是错误的。这不是一个最小的例子(它包含一些调试打印),因为我不知道它为什么会发生并且错误并不总是在同一部分。
// in header
// this helped somehow
#define EIGEN_DONT_VECTORIZE
#define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT
// ***********************************
#include <iostream>
#include <numeric>
#include <array>
#include <vector>
#include <Eigen/Dense>
#include <Eigen/StdVector>
#include "matrix_types.h"
#include "camera.h"
// *******************************************************************************
// Vector9d is a typedef
// in cpp
Vector9d _z(const Camera& cam, const Vector9d& derivX, int x_dir, int y_dir, const std::function<double(const Ray&)>& depthTest)
Eigen::IOFormat HeavyFmt(Eigen::FullPrecision, 0, ", ", ",\n", "[", "]", "[", "]");
Matrix9d M0 = OpticalFlow::M(cam, x_dir, y_dir, depthTest);
std::cout << "M_\n" << M0.format(HeavyFmt) << "\n" <<std::endl;
Vector9d z = M0 * derivX;
return z;
std::vector<Vector9d, Eigen::aligned_allocator<Vector9d>> OpticalFlow::GradPathError(const std::vector<Camera>& pathPositions, int x_dir, int y_dir, const std::function<double(const Ray&)>& depthTest, double h)
int n = pathPositions.size()-1;
Eigen::IOFormat HeavyFmt(Eigen::FullPrecision);
Eigen::IOFormat HeavyMtxFmt(Eigen::FullPrecision, 0, ", ", ",\n", "[", "]", "[", "]");
std::vector<Vector9d, Eigen::aligned_allocator<Vector9d>> gradPE;
gradPE.reserve(n+1);
// save values that will be used more often in calculations
std::vector<Vector9d, Eigen::aligned_allocator<Vector9d>> derivXs;
std::vector<Vector9d, Eigen::aligned_allocator<Vector9d>> zs;
std::vector<std::array<Matrix9d, 9>> gradMs;
derivXs.reserve(n+1);
zs.reserve(n+1);
gradMs.reserve(n+1);
for(int i = 0; i<n+1; ++i)
derivXs.push_back(_derivCamPath(pathPositions, i));
Camera cam = pathPositions[i];
Vector9d derivX = _derivCamPath(pathPositions, i);
zs.push_back(_z(cam, derivX, x_dir, y_dir, depthTest)); // <--- crashed here, if vectorization not turned off
gradMs.push_back(GradM(cam, x_dir, y_dir, depthTest, h));
for(int i = 0; i<n+1; ++i)
Vector9d derivZ = _derivZ(zs, i);
std::cout << "Zt_" << i << "\n" << derivZ.format(HeavyFmt) << "\n" << std::endl;
gradPE.push_back(1.0/(n+1) * _w(derivZ, derivXs[i], gradMs[i]));
// if this is included and vectorization turned off, it doesn't crash
// std::cout << "end" << std::endl;
return gradPE; // <-- crash here if vectorization is off
我希望有人可以帮助我找到原因,或者我可以尝试进一步追踪它。我对 C++ 不是很熟悉,所以代码可能有明显的问题。
【问题讨论】:
在gcc.gnu.org/onlinedocs/gcc/Option-Summary.html 中查找“对齐”相关标志 我在使用 SSE 的模块中遇到了类似的问题,当我切换到不同的编译器时,它开箱即用地解决了,但在此之前我设法修复了错误强制结构与编译器标志对齐。我不知道如何将这些传递给 pybind。 谢谢,我去看看。我想我在某处找到了与 Eigen 和对齐问题相关的编译器选项,但必须再次查找。 【参考方案1】:我想我找到了原因。
./blender(_ZN5Eigen8IOFormatD1Ev+0xd3) [0x2041673]
这一行实际上以不那么可读的格式命名了罪魁祸首。我使用 gdb 调试 Blender 的 python 调用,在回溯中,同一行是#0 0x0000000002041673 in Eigen::IOFormat::~IOFormat() ()
问题是我在我的程序中使用Eigen::IOFormat
来调试打印矩阵和向量,以便更轻松地复制到另一个我只想检查值是否正确的程序中。您可以在我在问题中发布的摘录代码中看到它。我只在这两个函数中使用它,段错误只发生在这两个函数中。可能还有其他问题,但就目前而言,它似乎有效。
【讨论】:
以上是关于C++ Python 模块在 Blender 中崩溃,但在 Python 控制台中没有的主要内容,如果未能解决你的问题,请参考以下文章