注意,NVRTC可以高速地编译代码,但是NVRTC并不支持C++且对代码的优化也不如NVCC,在配置较差的电脑上可以用它替代NVCC作为学习用的工具,大型工程尽量避免使用。
我们在编译CUDA工程时,会发现比C++代码的编译慢上许多,这是由于NVCC(CUDA/C++编译器)造成的,它可以兼容地编译C++代码与CUDA-C代码,但是十分低效。
我们可以用CUDA学习笔记(1)中的代码实验一下,对“kernel.cu”右键→属性,可以看到编译器是“CUDA C/C++”,然后先“清理解决方案”再“重新生成解决方案”,发现这时候会等待一段不短的时间。(在我的电脑上接近30秒)显然,这大大降低了我们的编程效率!
相对于C++编译器,它可以编译核函数,并且编译地很慢!当我们不使用核函数时,完全没必要用他。
现在我们将编译器换成“C/C++ 编译器”,重复先“清理解决方案”再“重新生成解决方案”的步骤,编译几乎瞬间完成!
那么有没有什么方法可以不使用“CUDA C/C++ 编译器”,又能高效地编译CUDA C的核函数呢? NVIDIA公司为此推出了NVRTC编译函数库。那么这个NVRTC比CUDA C编译器都有什么优点呢,NVIDIA的原话是:
NVRTC is a runtime compilation library for CUDA C++. It accepts CUDA C++ source code in character string form and creates handles that can be used to obtain the PTX. The PTX string generated by NVRTC can be loaded by cuModuleLoadData and cuModuleLoadDataEx, and linked with other modules by cuLinkAddData of the CUDA Driver API. This facility can often provide optimizations and performance not possible in a purely offline static compilation.
In the absence of NVRTC (or any runtime compilation support in CUDA), users needed to spawn a separate process to execute nvcc at runtime if they wished to implement runtime compilation in their applications or libraries, and, unfortunately, this approach has the following drawbacks:
The compilation overhead tends to be higher than necessary, and End users are required to install nvcc and related tools which make it complicated to distribute applications that use runtime compilation.
NVRTC addresses these issues by providing a library interface that eliminates overhead associated with spawning separate processes, disk I/O, etc., while keeping application deployment simple.
简单地说,我们可以用NVRTC编译库中的库函数来编译CUDA的核函数,这样就可以避免使用“CUDA C/C++ 编译器”,从而提高编译速度和编程效率。
现在我们将CUDA学习笔记(2)中的内容以C++调用NVRTC编译库的形式实现。
新建一个CUDA工程,必须添加对应的包含目录“CUDA安装目录\CUDA Samples\v9.0\common\inc”以及附加依赖项“cuda.lib”和“nvrtc.lib”。
我们在工程下添加两个文件,“main_code.cpp”和“kernel.cu”。
然后编辑这两个文件的属性,将“kernel.cu”设置为“不参与生成”,将“main_code.cpp”设置为“C/C++编译器”。
- “kernel.cu”中仅存放核函数的代码,且不参与工程编译!
- “main_code.cpp”中编写我们的C++代码,通过调用NVRTC编译库函数读取、编译核函数代码,并完成显存管理、重置GPU等操作。由C/C++编译器编译。
我们在“main_code.cpp”代码中包含对应的头文件。
// C/C++ IO
#include <stdio.h>
#include <iostream>
using namespace std;
// For the CUDA runtime routines (prefixed with "cuda_")
#include <cuda_runtime.h>
#include <cuda.h>
// helper functions and utilities to work with CUDA