我正在尝试在linux下使用MATLAB mex中的CUDA代码。使用“整个程序编译”模式,它对我有用。我在Nsight内部采取以下两个步骤:
(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文件,它仍然可以编译。
编辑:
我想出了如何手动链接到可以在MATLAB下正确运行的mex可执行文件,但我还没想出如何在Nsight下自动执行,我可以在“整个程序编译”模式下。这是我的方法:
(1)从构建中排除包含mexFunction条目的cpp文件。使用命令“mex -c”手动编译它。
(2)将“-fPIC”作为编译器选项添加到其余的.cpp或.cu文件中,然后单独编译,每个都生成.o文件。
(3)链接失败,因为找不到主函数。我们没有它,因为我们使用mexFunction并且它被排除在外。这没关系,我把它留在那里。
(4)按照以下帖子中的方法手动将.o文件链接到设备对象文件
cuda shared library linking: undefined reference to cudaRegisterLinkedBinary
例如,如果步骤(2)产生a.o和b.o,我们在这里做
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)的原因是因为它涉及两个命令,我不知道如何将它们放入。如果您知道如何执行这些操作,请告诉我。谢谢!
答案 0 :(得分:3)
好的,我找到了解决方案。以下是在Nsight中使用“单独编译模式”编译mex程序的完整步骤:
在项目级别,更改以下内容的构建选项:
-fPIC
。-dlink -Xcompiler '-fPIC'
添加到链接器“NVCC Linker”的“专家设置”“命令行模式”o
添加到“构建工件” - > “工件扩展”,因为在最后一步中-dlink
我们将输出设为.o
文件。mex -cxx -o path_to_mex_bin/mex_bin_filename ./*.o ./src/*.o -lcudadevrt
添加到“Post Build Steps”,(添加其他必要的库)更新:在我的实际项目中,我将最后一步移动到MATLAB中的.m文件中,否则如果我在mex程序运行时执行此操作,则可能导致MATLAB崩溃。
对于需要使用mex编译的文件,请为每个文件更改这些构建选项:
GCC C++ Compiler
。 GCC C++ Compiler
并将命令更改为mex
${COMMAND} -c -outdir "src" ${INPUTS}
其他几点说明:
(1)必须在mex编译器中隐藏Cuda特定的细节(例如内核函数和对内核函数的调用)。所以它们应该放在.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 :(得分:1)
首先,应该可以将Night设置为使用自定义Makefile ,而不是自动生成它。请参阅Setting Nsight to run with existing Makefile project。
一旦我们有了自定义Makefile,就可以自动化(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
包含mxFunction
但helper.c
不包含。{/ p>
编辑:您可以在自动编译系统中实现相同的效果。右键单击每个源文件并选择属性,您将获得一个窗口,您可以在其中为该单个文件添加一些编译选项。对于链接选项,请打开项目的属性。做一些实验并注意控制台中显示的实际编译命令。根据我的经验,自定义选项有时会以一种奇怪的方式与自动系统交互。如果这个方法对你来说太麻烦了,我建议你制作一个自定义的Makefile;这样,至少我们不会受到意想不到的副作用。