2016-09-19 8 views
1

У меня есть следующий минимальный .cu файл«неизвестная ошибка» на первом cudaMalloc если CUBLAS присутствует в ядре

#include <cuda_runtime_api.h> 
#include <cublas_v2.h> 
#include <cstdio> 

__global__ void test() 
{ 
    cublasHandle_t handle = nullptr; 
    cublasCreate(&handle); 
} 

int main(int, char**) 
{ 
    void * data = nullptr; 
    auto err = cudaMalloc(&data, 256); 
    printf("%s\n", cudaGetErrorString(err)); 
    return 0; 
} 

Как вы можете видеть, test ядро ​​даже и не называется, однако cudaMalloc возвращается 30 (неизвестная ошибка). Файл компилируется с разделяемой компиляцией (требуется для динамического параллелизма) и вычислительной способности 5.2 (также пытался 3.5 и 5.0, что ничего не меняло). Удаление вызова на cublasCreate вызывает cudaMalloc для возврата 0 (без ошибок).

В чем может быть причина? И как я могу это исправить? Мне нужно вызвать CUBLAS из ядра с использованием динамического параллелизма which is theoretically supported, поэтому «просто удалить звонок» не является вариантом.

Вот соответствующая CMakeLists.txt:

cmake_minimum_required(VERSION 3.3 FATAL_ERROR) 
project(CublasError) 

find_package(CUDA REQUIRED) 

set(CUDA_SEPARABLE_COMPILATION ON) 
set(CUDA_NVCC_FLAGS --gpu-architecture=compute_52 -Xptxas=-v) 
list(APPEND CUDA_NVCC_FLAGS_DEBUG -G -keep -O0) 

cuda_add_executable(${PROJECT_NAME} main.cu) 
cuda_add_cublas_to_target(${PROJECT_NAME}) 

# FindCUDA.cmake does not automatically add (or find) cudadevrt which is required when separable compilation is on 
if(CUDA_SEPARABLE_COMPILATION) 
    get_filename_component(CUDA_LIB_PATH ${CUDA_CUDART_LIBRARY} DIRECTORY) 
    find_library(CUDA_cudadevrt_LIBRARY cudadevrt PATHS ${CUDA_LIB_PATH}) 
    target_link_libraries(${PROJECT_NAME} ${CUDA_cudadevrt_LIBRARY}) 
endif() 

Вот набор теоретически подобных команд компиляции (результат, по крайней мере такой же):

nvcc -dc --gpu-architecture=compute_52 -m64 main.cu -o main.dc.obj 
nvcc -dlink --gpu-architecture=compute_52 -m64 main.dc.obj -o main.obj 
link /SUBSYSTEM:CONSOLE /LIBPATH:"%CUDA_PATH%\lib\x64" main.obj main.dc.obj cudart_static.lib cudadevrt.lib cublas.lib cublas_device.lib 
+0

Если я не ошибаюсь, это было бы невозможно скомпилировать этот источник, который вы выложили в исполняемый файл и запустить его. Не могли бы вы изменить свой вопрос, чтобы объяснить, как вы компилируете и запускаете этот источник, чтобы воспроизвести проблему? – talonmies

+0

Почему это невозможно? Он просто компилируется с использованием 'nvcc' – Joe

+0

. Измените точную команду компиляции и версию компилятора, которую вы используете в своем вопросе. AFAIK для отдельной траектории компиляции не может иметь «основной» и отдельно скомпилированный код ядра в том же файле – talonmies

ответ

1

Оказывается, что nvcc -dlink не сообщать о недостатках зависимостей и просто радостно продолжать, не испуская ошибок. Решение проблемы заключается в том, что cublas_device.lib должны быть связаны как во время хоста, соединяющего и связывание устройства, то есть команды компиляции должен выглядеть следующим образом:

nvcc -dc --gpu-architecture=compute_52 -m64 main.cu -o main.dc.obj 
nvcc -dlink --gpu-architecture=compute_52 -m64 -lcublas_device main.dc.obj -o main.obj 
link /SUBSYSTEM:CONSOLE /LIBPATH:"%CUDA_PATH%\lib\x64" main.obj main.dc.obj cudart_static.lib cudadevrt.lib cublas.lib cublas_device.lib 

Кроме того, nvcc -dlink зависит порядок, но в обратном порядке, что один используется от ld: -lcublas_device должен указывать до требуемых объектных файлов.

На стороне CMake вещей cuda_add_cublas_to_target не добавляет cublas_device.lib к команде соединения с устройством и добавляет ее только к команде хост-ссылки. В качестве временного решения, добавьте зависимость явно список NVCC флагов:

list(APPEND CUDA_NVCC_FLAGS -lcublas_device) 
+0

С помощью инструментальной линейки linux ваши инструкции не работают с отсутствующей зависимостью на этапе соединения с устройством. Я думаю, что вам действительно нужна компиляция устройства и глобальная ссылка (поэтому нет ссылки на устройство), чтобы сделать рабочий исполняемый файл. Мое замешательство в том, будет ли это работать, происходит на этапе компиляции устройства.Я на 99% уверен, что в более ранних версиях цепочки инструментов, которые не будут вызывать код какого-либо устройства, так что 'main' будет отсутствовать, а затем у вас должны были быть попытки компиляции main без дубликатов. Но привязка к устройству является тонкой и легко ошибиться, как вы видели здесь. – talonmies

+0

Да, возможно сделать последние два шага за один вызов, но cmake создает два отдельных вызова. Должно быть возможно только linux. – Joe