2017-04-26 121 views
3

我在MATLAB MEX代码中使用CUDA Thrust库时遇到了问题。在MATLAB MEX文件中使用Thrust运行时链接程序错误

我有一个外部运行良好的例子,但是如果我编译并运行它作为MEX文件,它会在运行时产生“丢失符号”错误。

它似乎特定于推力库。如果不是thrust::device_vector我使用cudaMalloccudaMemcpycublasSetVector然后一切都很好。

最小示例

thrustDemo.cu:

#ifdef MATLAB_MEX_FILE 
    #include "mex.h" 
    #include "gpu/mxGPUArray.h" 
#endif 
#include <thrust/device_vector.h> 
#include <vector> 

void thrustDemo() { 
    std::vector<double> foo(65536, 3.14); 
    thrust::device_vector<double> device_foo(foo); 
} 

#ifdef MATLAB_MEX_FILE 
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray const *prhs[]) { 
    thrustDemo(); 
} 
#else 
int main(void) { thrustDemo(); } 
#endif 

问题

我可以在命令行(nvcc thrustDemo.cu)编译此并运行生成的可执行文件就好了。

当我尝试(从MATLAB R2017a内mexcuda thrustDemo.cu)建立这个作为一个MATLAB MEX文件,它编译和链接就好:

>> mexcuda thrustDemo.cu 
Building with 'nvcc'. 
MEX completed successfully. 

但是当我尝试运行它,我得到以下错误:

>> thrustDemo() 
Invalid MEX-file '/home/kqs/thrustDemo.mexa64': 
Missing symbol '_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5emptyEv' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt12length_errorC1EPKc' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt13runtime_errorC2EPKc' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEPKc' required by '/home/kqs/thrustDemo.mexa64' 
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLERKS4_' required by '/home/kqs/thrustDemo.mexa64'. 

这对我来说很陌生;有人可以告诉我这意味着什么吗?这些看起来像链接器错误,但它们是在运行时生成的。另外,我认为Thrust是一个模板库,那么链接到哪里?

最后,用cudaMalloccudaMemcpycublasSetVector代替thrust::device_vector就行了。所以现在我被我的代码卡住了一堆cudaMalloc,这似乎......令人厌恶。我真的很想能够使用Thrust。

版本

MATLAB R2017a

nvcc V8.0.61,gcc 5.4.0,Ubuntu的16.04.2

NVIDIA驱动375.39,1060 GTX显卡(计算能力6.1)

更新:ldd输出

每注释,我检查了依赖关系的t使用ldd thrustDemo.mexa64他MEX文件:

linux-vdso.so.1 => (0x00007ffdd35ea000) 
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f097eccf000) 
libcudart.so.8.0 => /usr/local/cuda-8.0/targets/x86_64-linux/lib/libcudart.so.8.0 (0x00007f097ea69000) 
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f097e852000) 
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f097e489000) 
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f097e180000) 
/lib64/ld-linux-x86-64.so.2 (0x0000562df178c000) 
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f097df7b000) 
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f097dd5e000) 
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f097db56000) 

我试图寻找这些丢失的标志之一,并且是能够找到它:

$ nm -D /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv" 
0000000000120be0 W _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv 

如此看来,MATLAB必须找错了地方。

+0

这不是一个运行时错误。加载mex文件时发生该错误。我不知道错误的原因。但是你应该能够在linux中使用ldd等工具检查你的mex文件来检查依赖关系。 – Navan

+0

这是某种破碎的C++/stdlib问题或主机编译器不匹配。涉及的函数是'std :: __ cxx11 :: basic_string ,std :: allocator > :: c_str()const'与CUDA无关 – talonmies

+0

我看到了;错误输出现在变得更有意义。我认为MATLAB倾向于使用自己的'libstdC++'版本,这可能是根本原因。谢谢你的评论。 – KQS

回答

4

事实证明,这与Thrust没有任何关系,但是MATLAB有它自己版本的C++标准库是一个问题。

感谢@Navan和@talonmies的有用评论。

解读错误

首先,MATLAB是当它加载MEX文件提出这些错误。 MEX文件具有外部依赖性,MATLAB无法找到它们。

检查这些依赖与Linux工具ldd,然后使用nm列出的符号通过这些库定义后,我发现libstdc++共享库的系统版本确实包含这些“失踪符号”。因此,为什么外部编译的版本工作得很好。

解决问题

问题的根源,那么,是MATLAB附带了自己的旧版本的libstdc++目前缺乏这些功能。知道了病根,我发现这样的问题:

How to tell mex to link with the libstdc++.so.6 in /usr/lib instead of the one in the MATLAB directory?

Version GLIBCXX_3.4.11 not found (required by buildW.mexglx)

其中描述说,确实成功地为我的问题的解决方法。

我特别推出MATLAB时使用LD_PRELOAD强制MATLAB使用其自己的副本系统libstdc++代替:

$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/local/MATLAB/R2017a/bin/matlab 

更新:一个更好的解决方案

事实证明,在乡亲GCC深知这种不兼容性和discuss it here的:

In the GCC 5.1 release libstdc++ introduced a new library ABI that includes new implementations of std::string and std::list. These changes were necessary to conform to the 2011 C++ standard which forbids Copy-On-Write strings and requires lists to keep track of their size.

In order to maintain backwards compatibility for existing code linked to libstdc++ the library's soname has not changed and the old implementations are still supported in parallel with the new ones. ... The _GLIBCXX_USE_CXX11_ABI macro (see Macros) controls whether the declarations in the library headers use the old or new ABI.

告诉gcc使用旧的ABI,我们只需要在包含任何库标题之前将_GLIBCXX_USE_CXX11_ABI定义为0,例如通过传递-D选项编译:

-D_GLIBCXX_USE_CXX11_ABI=0 

为了完整起见,我会提到我的全mexcuda调用如下:

nvcc_opts = [... 
    '-gencode=arch=compute_30,code=sm_30 ' ... 
    '-gencode=arch=compute_50,code=sm_50 ' ... 
    '-gencode=arch=compute_60,code=sm_60 ' ... 
    '-std=c++11 ' ... 
    '-D_GLIBCXX_USE_CXX11_ABI=0 ' % MATLAB's libstdc++ uses old library ABI 
    ]; 
mexcuda_opts = { 
    '-lcublas'      % Link to cuBLAS 
    '-lmwlapack'     % Link to LAPACK 
    '-lcufft'      % Link to cuFFT 
    ['NVCCFLAGS="' nvcc_opts '"'] 
    '-L/usr/local/cuda/lib64'  % Location of CUDA libraries 
    }; 
mexcuda(mexcuda_opts{:}, src_file);