Подтвердить что ты не робот

Cuda shared library linking: undefined ссылка на cudaRegisterLinkedBinary

Цель:

  • создать общую библиотеку, содержащую мои ядра CUDA с оболочкой и заголовком CUDA.
  • создать исполняемый файл test для общей библиотеки.

Проблема

  • общая библиотека MYLIB.so кажется компилируемой в порядке. (без проблем).
  • Ошибка при связывании:

./libMYLIB.so: undefined reference to __cudaRegisterLinkedBinary_39_tmpxft_000018cf_00000000_6_MYLIB_cpp1_ii_74c599a1

упрощенный make файл:

libMYlib.so :  MYLIB.o
    g++  -shared  -Wl,-soname,libMYLIB.so  -o libMYLIB.so    MYLIB.o  -L/the/cuda/lib/dir  -lcudart


MYLIB.o : MYLIB.cu   MYLIB.h
    nvcc  -m64   -arch=sm_20 -dc  -Xcompiler '-fPIC'  MYLIB.cu  -o  MYLIB.o  -L/the/cuda/lib/dir  -lcudart


test : test.cpp  libMYlib.so
        g++   test.cpp  -o test  -L.  -ldl -Wl,-rpath,.   -lMYLIB  -L/the/cuda/lib/dir  -lcudart

действительно

nm libMYLIB.so показывает, что все функции CUDA api: undefined символы:

         U __cudaRegisterFunction
         U __cudaRegisterLinkedBinary_39_tmpxft_0000598c_00000000_6_CUPA_cpp1_ii_74c599a1
         U cudaEventRecord
         U cudaFree
         U cudaGetDevice
         U cudaGetDeviceProperties
         U cudaGetErrorString
         U cudaLaunch
         U cudaMalloc
         U cudaMemcpy

Итак, CUDA каким-то образом не привязана к общей библиотеке MYLIB.so Что мне не хватает?


CUDA даже не связался с объектным файлом:

nm MYLIB.o

         U __cudaRegisterFunction
         U __cudaRegisterLinkedBinary_39_tmpxft_0000598c_00000000_6_CUPA_cpp1_ii_74c599a1
         U cudaEventRecord
         U cudaFree
         U cudaGetDevice
         U cudaGetDeviceProperties
         U cudaGetErrorString
         U cudaLaunch
         U cudaMalloc
         U cudaMemcpy

(как указано выше)

4b9b3361

Ответ 1

Здесь приведен пример совместного создания объектов linux вдоль указанных линий:

  • создать общую библиотеку, содержащую мои ядра CUDA, которая имеет CUDA-бесплатная оболочка/заголовок.
  • создать тестовый исполняемый файл для общей библиотеки.

Сначала разделяемая библиотека. Команды сборки для этого следующие:

nvcc -arch=sm_20 -Xcompiler '-fPIC' -dc test1.cu test2.cu
nvcc -arch=sm_20 -Xcompiler '-fPIC' -dlink test1.o test2.o -o link.o
g++ -shared -o test.so test1.o test2.o link.o -L/usr/local/cuda/lib64 -lcudart

Кажется, вам не хватает второго шага выше в вашем файле makefile, но я не проанализировал, есть ли какие-либо другие проблемы с вашим make файлом.

Теперь для тестового исполняемого файла команды сборки следующие:

g++ -c main.cpp
g++ -o testmain main.o test.so

Чтобы запустить его, просто выполните исполняемый файл testmain, но убедитесь, что библиотека test.so находится на вашем LD_LIBRARY_PATH.

Это файлы, которые я использовал для тестирования:

test1.h:

int my_test_func1();

test1.cu:

#include <stdio.h>
#include "test1.h"

#define DSIZE 1024
#define DVAL 10
#define nTPB 256

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

__global__ void my_kernel1(int *data){
  int idx = threadIdx.x + (blockDim.x *blockIdx.x);
  if (idx < DSIZE) data[idx] =+ DVAL;
}

int my_test_func1(){

  int *d_data, *h_data;
  h_data = (int *) malloc(DSIZE * sizeof(int));
  if (h_data == 0) {printf("malloc fail\n"); exit(1);}
  cudaMalloc((void **)&d_data, DSIZE * sizeof(int));
  cudaCheckErrors("cudaMalloc fail");
  for (int i = 0; i < DSIZE; i++) h_data[i] = 0;
  cudaMemcpy(d_data, h_data, DSIZE * sizeof(int), cudaMemcpyHostToDevice);
  cudaCheckErrors("cudaMemcpy fail");
  my_kernel1<<<((DSIZE+nTPB-1)/nTPB), nTPB>>>(d_data);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel");
  cudaMemcpy(h_data, d_data, DSIZE * sizeof(int), cudaMemcpyDeviceToHost);
  cudaCheckErrors("cudaMemcpy 2");
  for (int i = 0; i < DSIZE; i++)
    if (h_data[i] != DVAL) {printf("Results check failed at offset %d, data was: %d, should be %d\n", i, h_data[i], DVAL); exit(1);}
  printf("Results check 1 passed!\n");
  return 0;
}

test2.h:

int my_test_func2();

test2.cu:

#include <stdio.h>
#include "test2.h"

#define DSIZE 1024
#define DVAL 20
#define nTPB 256

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

__global__ void my_kernel2(int *data){
  int idx = threadIdx.x + (blockDim.x *blockIdx.x);
  if (idx < DSIZE) data[idx] =+ DVAL;
}

int my_test_func2(){

  int *d_data, *h_data;
  h_data = (int *) malloc(DSIZE * sizeof(int));
  if (h_data == 0) {printf("malloc fail\n"); exit(1);}
  cudaMalloc((void **)&d_data, DSIZE * sizeof(int));
  cudaCheckErrors("cudaMalloc fail");
  for (int i = 0; i < DSIZE; i++) h_data[i] = 0;
  cudaMemcpy(d_data, h_data, DSIZE * sizeof(int), cudaMemcpyHostToDevice);
  cudaCheckErrors("cudaMemcpy fail");
  my_kernel2<<<((DSIZE+nTPB-1)/nTPB), nTPB>>>(d_data);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel");
  cudaMemcpy(h_data, d_data, DSIZE * sizeof(int), cudaMemcpyDeviceToHost);
  cudaCheckErrors("cudaMemcpy 2");
  for (int i = 0; i < DSIZE; i++)
    if (h_data[i] != DVAL) {printf("Results check failed at offset %d, data was: %d, should be %d\n", i, h_data[i], DVAL); exit(1);}
  printf("Results check 2 passed!\n");
  return 0;
}

main.cpp:

#include <stdio.h>

#include "test1.h"
#include "test2.h"

int main(){

  my_test_func1();
  my_test_func2();
  return 0;
}

Когда я компилирую в соответствии с приведенными командами и запускаю ./testmain, я получаю:

$ ./testmain
Results check 1 passed!
Results check 2 passed!

Обратите внимание, что если вы предпочитаете, вы можете сгенерировать libtest.so вместо test.so, а затем вы можете использовать модифицированную последовательность сборки для тестового исполняемого файла:

g++ -c main.cpp
g++ -o testmain main.o -L. -ltest

Я не верю, что это имеет какое-то значение, но это может быть более знакомый синтаксис.

Я уверен, что есть несколько способов сделать это. Это просто пример. Вы также можете просмотреть соответствующий раздел руководства nvcc, а также просмотреть examples.

РЕДАКТИРОВАТЬ: Я тестировал это в соответствии с cuda 5.5 RC, и заключительный шаг ссылки на приложение жаловался на то, что не обнаружил cudart lib (warning: libcudart.so.5.5., needed by ./libtest.so, not found). Однако следующая относительно простая модификация (пример Makefile) должна работать либо с cuda 5.0, либо с cuda 5.5.

Makefile:

testmain : main.cpp  libtest.so
        g++ -c main.cpp
        g++ -o testmain  -L.  -ldl -Wl,-rpath,.   -ltest -L/usr/local/cuda/lib64 -lcudart main.o

libtest.so : link.o
        g++  -shared -Wl,-soname,libtest.so -o libtest.so    test1.o test2.o link.o  -L/usr/local/cuda/lib64  -lcudart

link.o : test1.cu test2.cu   test1.h test2.h
        nvcc  -m64   -arch=sm_20 -dc  -Xcompiler '-fPIC'  test1.cu test2.cu
        nvcc  -m64   -arch=sm_20 -Xcompiler '-fPIC' -dlink test1.o test2.o -o link.o

clean :
        rm -f testmain test1.o test2.o link.o libtest.so main.o

Ответ 2

Вы пытались явно отключить код переключаемого устройства? т.е. -rdc=false? Я получил undefined reference to __cudaRegisterLinkedBinaryWhatever с -rdc=true, и он ушел, когда я удалил его. Хотя мне недостаточно эксперта, чтобы объяснить, что именно происходит с этим.

Ответ 3

Другие ответы не помогли мне (возможно, потому, что я использовал cuda 10). Решение, которое работало для меня, заключалось в компиляции файлов cuda:

nvcc -dc -o cuda_file.o cuda_file.cu

Затем компилируем файл c++ как:

g++ -c -o cpp_file.o cpp_file.cpp

И, наконец, связывание всех с помощью nvcc:

nvcc -o my_prog cpp_file.o cuda_file.o -lcudart -lcuda -L<other stuff>

Не используйте этот код буквально. Но ядро решения ошибки заключалось в использовании nvcc вместо g++ на заключительном этапе связывания.