2017-04-26 122 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);