Я пишу ядро CUDA, которое компилируется во время выполнения с использованием NVRTC (CUDA версия 9.2 с NVRTC версия 7.5), которому требуется заголовок stdint.h
, чтобы иметь типы int32_t
и т. Д.
Если я напишу исходный код ядра без include, он будет работать правильно.Например, ядро
extern "C" __global__ void f() { ... }
Компилируется в код PTX, где f определяется как .visible .entry f
.
Но если исходный код ядра
#include <stdint.h>
extern "C" __global__ void f() { ... }
, он сообщаетA function without execution space annotations (__host__/__device__/__global__) is considered a host function, and host functions are not allowed in JIT mode.
(также без extern "C"
).
Передача -default-device
делает код PTX .visible .func f
, поэтому функция не может быть вызвана с хоста.
Есть ли способвключить заголовки в исходный код и все еще иметь функцию ввода __global__
?Или, альтернативно, способ узнать, какое соглашение о целочисленном размере используется компилятором NVRTC, чтобы типы int32_t
и т. Д. Можно было определять вручную?
Редактировать: Пример программыэто показывает проблему:
#include <cstdlib>
#include <string>
#include <vector>
#include <memory>
#include <cassert>
#include <iostream>
#include <cuda.h>
#include <cuda_runtime.h>
#include <nvrtc.h>
[[noreturn]] void fail(const std::string& msg, int code) {
std::cerr << "error: " << msg << " (" << code << ')' << std::endl;
std::exit(EXIT_FAILURE);
}
std::unique_ptr<char[]> compile_to_ptx(const char* program_source) {
nvrtcResult rv;
// create nvrtc program
nvrtcProgram prog;
rv = nvrtcCreateProgram(
&prog,
program_source,
"program.cu",
0,
nullptr,
nullptr
);
if(rv != NVRTC_SUCCESS) fail("nvrtcCreateProgram", rv);
// compile nvrtc program
std::vector<const char*> options = {
"--gpu-architecture=compute_30"
};
//options.push_back("-default-device");
rv = nvrtcCompileProgram(prog, options.size(), options.data());
if(rv != NVRTC_SUCCESS) {
std::size_t log_size;
rv = nvrtcGetProgramLogSize(prog, &log_size);
if(rv != NVRTC_SUCCESS) fail("nvrtcGetProgramLogSize", rv);
auto log = std::make_unique<char[]>(log_size);
rv = nvrtcGetProgramLog(prog, log.get());
if(rv != NVRTC_SUCCESS) fail("nvrtcGetProgramLog", rv);
assert(log[log_size - 1] == '\0');
std::cerr << "Compile error; log:\n" << log.get() << std::endl;
fail("nvrtcCompileProgram", rv);
}
// get ptx code
std::size_t ptx_size;
rv = nvrtcGetPTXSize(prog, &ptx_size);
if(rv != NVRTC_SUCCESS) fail("nvrtcGetPTXSize", rv);
auto ptx = std::make_unique<char[]>(ptx_size);
rv = nvrtcGetPTX(prog, ptx.get());
if(rv != NVRTC_SUCCESS) fail("nvrtcGetPTX", rv);
assert(ptx[ptx_size - 1] == '\0');
nvrtcDestroyProgram(&prog);
return ptx;
}
const char program_source[] = R"%%%(
//#include <stdint.h>
extern "C" __global__ void f(int* in, int* out) {
out[threadIdx.x] = in[threadIdx.x];
}
)%%%";
int main() {
CUresult rv;
// initialize CUDA
rv = cuInit(0);
if(rv != CUDA_SUCCESS) fail("cuInit", rv);
// compile program to ptx
auto ptx = compile_to_ptx(program_source);
std::cout << "PTX code:\n" << ptx.get() << std::endl;
}
Когда //#include <stdint.h>
в исходном коде ядра не комментируется, он больше не компилируется.Когда //options.push_back("-default-device");
не комментируется, он компилируется, но не помечает функцию f
как .entry
.
CMakeLists.txt для его компиляции (требуется API драйвера CUDA + NVRTC)
cmake_minimum_required(VERSION 3.4)
project(cudabug CXX)
find_package(CUDA REQUIRED)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED 14)
add_executable(cudabug cudabug.cc)
include_directories(SYSTEM ${CUDA_INCLUDE_DIRS})
link_directories(${CUDA_LIBRARY_DIRS})
target_link_libraries(cudabug PUBLIC ${CUDA_LIBRARIES} nvrtc cuda)