2014-01-19 76 views
2

我試圖在linux下使用MATLAB mex下的CUDA代碼。使用「整個程序編譯」模式,它對我有用。我在Nsight中採取以下兩個步驟:mex鏈接的獨立編譯模式下的cuda代碼

(1)將「-fPIC」作爲編譯器選項添加到每個.cpp或.cu文件,然後分別編譯它們,每個文件生成一個.o文件。 (2)將鏈接器命令設置爲「mex」並添加「-cxx」以表示所有.o輸入文件的類型都是cpp文件,併爲cuda添加庫路徑。還要添加一個包含mexFunction條目的cpp文件作爲附加輸入。

這工作良好,導致mex文件在MATLAB下運行良好。之後,當我需要使用動態並行時,我必須切換到Nsight中的「單獨編譯模式」。我嘗試了上面的同樣的事情,但鏈接器產生了很多錯誤的引用,這是我無法解決的。

然後我檢查了「獨立編譯」模式的編譯和鏈接步驟。我對它正在做的事情感到困惑。看起來,Nsight爲每個.cpp或.cu文件執行兩個編譯步驟,並生成.o文件和.d文件。就像這樣:

/usr/local/cuda-5.5/bin/nvcc -O3 -gencode arch=compute_35,code=sm_35 -odir "src" -M -o "src/tn_matrix.d" "../src/tn_matrix.cu" 
/usr/local/cuda-5.5/bin/nvcc --device-c -O3 -gencode arch=compute_35,code=compute_35 -gencode arch=compute_35,code=sm_35 -x cu -o "src/tn_matrix.o" "../src/tn_matrix.cu" 

的連接命令是這樣的:

/usr/local/cuda-5.5/bin/nvcc --cudart static --relocatable-device-code=true -gencode arch=compute_35,code=compute_35 -gencode arch=compute_35,code=sm_35 -link -o "test7" ./src/cu_base.o ./src/exp_bp_wsj_dev_mex.o ./src/tn_main.o ./src/tn_matlab_helper.o ./src/tn_matrix.o ./src/tn_matrix_lib_dev.o ./src/tn_matrix_lib_host.o ./src/tn_model_wsj_dev.o ./src/tn_model_wsj_host.o ./src/tn_utility.o -lcudadevrt -lmx -lcusparse -lcurand -lcublas 

有趣的是鏈接器不走.D文件作爲輸入。所以我不確定它是如何處理這些文件的,以及如何在鏈接時使用「mex」命令處理它們?

另一個問題是,鏈接階段有很多我不明白的選項(--cudart static --relocatable-device-code = true),我想這是我無法使它工作的原因在「整個程序編譯」模式下。所以我嘗試了以下內容:

(1)以與帖子開頭相同的方式進行編譯。 (2)保留Nsight提供的鏈接命令,但改爲使用「-shared」選項,以便鏈接器生成一個lib文件。 (3)通過輸入lib文件和另一個包含mexFunction條目的cpp文件調用mex。

這種方式mex編譯工作,它產生一個mex可執行文件作爲輸出。但是,在MATLAB下運行生成的mex可執行文件會立即產生分段錯誤並導致MATLAB崩潰。

我不確定這種連接方式是否會導致任何問題。更奇怪的是,我發現mex鏈接步驟似乎沒有檢查可執行文件的完整性即可完成,因爲即使我錯過了mexFunction將使用的某個函數的.cpp文件,它仍然會編譯。

編輯:

我想出如何手動鏈接成一個可執行MEX可MATLAB下運行正常,但我還沒有想出怎麼做,下Nsight自動,這是我可以在「全程序編譯「模式。這是我的方法:

(1)排除構建包含mexFunction條目的cpp文件。用命令「mex -c」手動編譯它。

(2)將「-fPIC」作爲編譯器選項添加到其餘的.cpp或.cu文件中,然後分別編譯它們,每個文件生成一個.o文件。

(3)鏈接將失敗,因爲它無法找到主要功能。我們沒有它,因爲我們使用mexFunction,它被排除在外。這並不重要,我只是把它留在那裏。

(4)按照在下面的柱的方法手動DLINK .o文件到一個設備對象文件

cuda shared library linking: undefined reference to cudaRegisterLinkedBinary

例如,如果步驟(2)產生A0和B0,這裏我們做

nvcc -gencode arch=compute_35,code=sm_35 -Xcompiler '-fPIC' -dlink a.o b.o -o mex_dev.o -lcudadevrt 

請注意,這裏輸出文件mex_dev.o應該不存在,否則上述命令將失敗。 (5)使用mex命令鏈接步驟(2)和步驟(4)中生成的所有.o文件,並提供所有必需的庫。

這可以工作並生成可運行的mex可執行文件。我無法在Nsight中自動執行步驟(1)的原因是,如果我將編譯命令更改爲「mex」,Nsight也將使用此命令生成依賴文件(問題文本中提到的.d文件)。我之所以不能在Nsight中自動執行步驟(4)和步驟(5),是因爲它涉及兩條命令,我不知道如何將它們放入。請讓我知道如果您知道如何執行這些操作。謝謝!

回答

2

好的,我想出瞭解決方案。以下是在Nsight中用「單獨編譯模式」編譯mex程序的完整步驟:

  1. 創建一個cuda項目。
  2. 在項目層面上,更改以下構建選項:在項目級「NVCC編譯」的編譯器選項上-fPIC

    • 開關。在我們正在最後一步神器擴展「因爲由-dlink -
    • 添加-dlink -Xcompiler '-fPIC'到「鏈接器」,「專家設置」的「命令行模式NVCC鏈接」
    • 添加字母o以「打造神器」>」輸出一個.o文件。
    • 添加mex -cxx -o path_to_mex_bin/mex_bin_filename ./*.o ./src/*.o -lcudadevrt到「後生成步驟」,(加上其他必要的庫)

    更新:在我的實際項目中,我提出的最後一步,在MATLAB一個.m文件,否則如果我去做了,而我的mex程序正在運行,可能會導致MATLAB崩潰。

  3. 對於文件需要與墨西哥進行編譯,改變這些構建選項爲他們每個人:

    • 變化的工具鏈編輯器,編譯器,以GCC C++ Compiler
    • 回的GCC C++ Compiler編譯器設置和改變命令mex
    • 更改命令線圖案以${COMMAND} -c -outdir "src" ${INPUTS}

幾個附加註釋:

(1)Cuda的具體細節(如內核函數和對內核函數的調用)必須隱藏在mex編譯器中。所以他們應該放在.cu文件而不是頭文件中。這是一個將涉及cuda細節的模板放入.cu文件的技巧。

在頭文件(例如,f.h),你只放了函數的聲明是這樣的:

template<typename ValueType> 
void func(ValueType x); 

添加一個名爲f.inc一個新的文件,其中包含定義

template<> 
void func(ValueType x) { 
    // possible kernel launches which should be hidden from mex 
} 

在源代碼文件(例如,f.cu)中,您將此

#define ValueType float 
#include "f.inc" 
#undef ValueType 

#define ValueType double 
#include "f.inc" 
#undef ValueType 

// Add other types you want. 

這個技巧可以很容易地推廣到模板類來隱藏細節。

(2)mex的具體細節也應該從cuda源文件中隱藏,因爲mex.h會改變一些系統函數的定義,如printf。所以包含「mex.h」的文件不應該出現在可能包含在cuda源文件中的頭文件中。 (3)在包含條目mexFunction的mex源代碼文件中,可以使用編譯器宏MATLAB_MEX_FILE來選擇性地編譯代碼段。通過這種方式,可以將源代碼文件編譯爲mex可執行文件或通常可執行文件,從而允許在沒有matlab的情況下在Nsight下進行調試。以下是在Nsight下構建多個目標的技巧:Building multiple binaries within one Eclipse project

1

首先,應該可以設置Night使用自定義Makefile而不是自動生成它。見Setting Nsight to run with existing Makefile project。 (1),(4)和(5)自動化。自定義Makefile的優點在於您確切知道將發生哪些編譯命令。

的精簡版的例子:

all: mx.mexa64 

mx.mexa64: mx.o 
    mex -o mx.mexa64 mx.o -L/usr/local/cuda/lib64 -lcudart -lcudadevrt 

mx.o: mxfunc.o helper.o 
    nvcc -arch=sm_35 -Xcompiler -fPIC -o mx.o -dlink helper.o mxfunc.o -lcudadevrt 

mxfunc.o: mxfunc.c 
    mex -c -o mxfunc.o mxfunc.c 

helper.o: helper.c 
    nvcc -arch=sm_35 -Xcompiler -fPIC -c -o helper.o helper.c 

clean: 
    rm -fv mx.mexa64 *.o 

...其中mxfunc.c包含mxFunctionhelper.c沒有。

編輯:您可能能夠在自動編譯系統中實現相同的效果。右鍵單擊每個源文件並選擇屬性,然後您將看到一個窗口,您可以在該窗口中爲該單個文件添加一些編譯選項。對於鏈接選項,打開項目的屬性。做一些實驗,並注意控制檯中顯示的實際編譯命令。根據我的經驗,自定義選項有時會以奇怪的方式與自動系統進行交互。如果這種方法對您來說太麻煩了,我建議您製作一個自定義的Makefile;這樣,至少我們不會被意想不到的副作用所吸引。

+0

感謝您的解決方案!不過,我不想使用自定義makefile解決方案,因爲我喜歡Eclipse提供的自動化管理工具。你知道如果我有一個自定義的makefile,那麼我可以稍後將它轉換爲Eclipse項目嗎? 對於mex,它有一個命令行版本,它和matlab裏面調用的一樣。 – shaoyl85

+0

^是的,我已經更新了示例以使用mex的命令行版本,這絕對看起來更好。我還會添加一些關於如何修改自動編譯系統的說明...... –

+0

我做了一些Google搜索,但是我沒有找到將自定義Makefile轉換爲託管項目的方法。我認爲這是因爲,像其他命令行工具一樣,Makefile提供了很大的靈活性。 –