我正在尝试在 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) 调用 mex,输入 lib 文件和另一个包含 mexFunction 条目的 cpp 文件。
这样,mex 编译就可以工作,并生成一个 mex 可执行文件作为输出。但是,在 MATLAB 下运行生成的 mex 可执行文件会立即产生分段错误并使 MATLAB 崩溃。
我不确定这种链接方式是否会导致任何问题。更奇怪的是,我发现 mex 链接步骤似乎很简单地完成,甚至没有检查可执行文件的完整性,因为即使我错过了 mexFunction 将使用的某些函数的 .cpp 文件,它仍然可以编译。
EDIT:
我弄清楚了如何手动链接到可以在 MATLAB 下正确运行的 mex 可执行文件,但我还没有弄清楚如何在 Nsight 下自动执行此操作,我可以在“整个程序编译”模式下执行此操作。这是我的方法:
(1) 从构建中排除包含 mexFunction 条目的 cpp 文件。使用命令“mex -c”手动编译它。
(2) 将“-fPIC”作为编译器选项添加到其余的每个.cpp 或.cu 文件中,然后分别编译它们,每个文件生成一个.o 文件。
(3) 由于找不到main函数,链接会失败。我们没有它,因为我们使用 mexFunction 并且它被排除在外。这并不重要,我就把它留在那里。
(4) 按照下面帖子中的方法手动将.o文件链接到设备目标文件中
cuda 共享库链接:对 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)的原因是因为它涉及两个命令,我不知道如何将它们放入。如果您知道如何执行这些操作,请告诉我。谢谢!