2013-04-17 9 views
5

Jak mogę oddzielić kod jądra cuda od innych kodów cpp w projekcie? Chcę zebrać wszystkie definicje jądra w jednym pliku, jak inne pliki cpp wywołujące je w razie potrzeby. Próbowałem napisać wszystkie jądra wewnątrz kernel.cu i wywoływać jądra przez dołączenie pliku kernel.cu, ale daje następujący błąd podczas kompilacji.jak zachować kod jądra w osobnym pliku .cu innym niż główny .cpp?

/usr/bin/ld: error: ./vector_summation.o: multiple definition of 

'perform_summation_method1(int*, int)' 
/usr/bin/ld: ./kernels.o: previous definition here 
/usr/bin/ld: error: ./vector_summation.o: multiple definition of '__device_stub__Z25perform_summation_method1Pii(int*, int)' 
/usr/bin/ld: ./kernels.o: previous definition here 
/usr/bin/ld: error: ./vector_summation.o: multiple definition of '__device_stub__Z25perform_summation_method2PiS_i(int*, int*, int)' 
/usr/bin/ld: ./kernels.o: previous definition here 
/usr/bin/ld: error: ./vector_summation.o: multiple definition of 'perform_summation_method2(int*, int*, int)' 
/usr/bin/ld: ./kernels.o: previous definition here 
/usr/bin/ld: error: ./vector_summation.o: multiple definition of '__device_stub__Z25perform_summation_method3PiS_i(int*, int*, int)' 
/usr/bin/ld: ./kernels.o: previous definition here 
/usr/bin/ld: error: ./vector_summation.o: multiple definition of 'perform_summation_method3(int*, int*, int)' 
/usr/bin/ld: ./kernels.o: previous definition here 

Odpowiedz

13

Robisz to zasadniczo tak samo, jak robisz to ze zwykłymi plikami/modułami cpp. W języku C++ normalnie nie ma jednego pliku .cpp w innym, jeśli chcesz uzyskać dostęp do funkcji z drugiego pliku. Uwzględniasz nagłówki, które zwykle zawierają tylko prototypy funkcji.

Oto przykład:

test.h:

void my_cuda_func(); 

main.cpp:

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

int main(){ 
    my_cuda_func(); 
    return 0; 
} 

test.cu:

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


__global__ void my_kernel(){ 
    printf("Hello!\n"); 
} 

void my_cuda_func(){ 
    my_kernel<<<1,1>>>(); 
    cudaDeviceSynchronize(); 
} 

użyciu następujących poleceń do zbudowania:

g++ -c main.cpp 
nvcc -arch=sm_20 -c test.cu 
g++ -L/usr/local/cuda/lib64 -lcudart -o test main.o test.o 

Oczywiście istnieją inne podejścia. Jeśli chcesz utworzyć łącze do C zamiast C++, musisz wziąć to pod uwagę. Jeśli chcesz wywoływać jądra bezpośrednio z innych modułów zamiast używać funkcji wrapper, musisz przekazać wszystkie swoje moduły przez nvcc zamiast g ++ (i wszystkie powinny być plikami .cu). Ponadto, jeśli chcesz mieć wiele plików z kodem urządzenia GPU (np. Definicje jądra), musisz zapoznać się z użyciem device code linker.

Dla kompletności, tutaj jest powyższy przykład ponownie pracował, aby pokazać, co zrobić, jeśli chcesz wszystkie definicje jądra w jednym pliku, ale być może powołać jądra bezpośrednio z innego modułu:

test.h:

__global__ void my_kernel(); 

main.cu:

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

int main(){ 
    my_kernel<<<1,1>>>(); 
    cudaDeviceSynchronize(); 
    return 0; 
} 

test.cu:

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


__global__ void my_kernel(){ 
    printf("Hello!\n"); 
} 

budować z:

nvcc -arch=sm_20 -c main.cu 
nvcc -arch=sm_20 -c test.cu 
nvcc -arch=sm_20 -o test main.o test.o 
1

Można utworzyć plik nagłówka CUDA *.cuh i dołączyć go jako standardowy cel. Nie umieszczałbym tylko jądra w osobnym pliku, a raczej łączę je z niektórymi funkcjami inicjującymi i umieszczam tylko te funkcje w nagłówku, ponieważ zwykle nie wywołuje się tylko jądra z kodu zewnętrznego, wywołuje się funkcję, która zajmuje się pamięć itd. i zazwyczaj zrobić nagłówki tak:

#ifndef __CUDAHEADER_CUH__ 
#define __CUDAHEADER_CUH__ 

/** Initialize cuda stuff */ 
void cudaInit(Data * host_data); 

/** Cleanup, frees resources used by the device. */ 
void cudaFinalize(); 

#endif 

a potem jest plik z jądrami, metod i urządzeń tych metod, które zajmują cuda rzeczy:

#include "cudaHeader.cuh" 

//some global variables like: 
Data * device_data; 

//some kernels and device functions: 
__global__ void someKernel(data * device_data) { 
    ... 
} 

void cudaInit(Data * host_data) { 
    some cudaMalloc() 
    some cudaMemcpy() 
    someKernel<<< gridRes, blockRes >>>(device_data); 
} 


void cudaFinalize() { 
    cudaFree(device_data); 
} 

ale istnieje więcej sposobów, jak radzić Twój kod...

-1

Pierwszy przykład: Myślę, że trzeba budować (ostatni wiersz) tak:

g++ -L/usr/local/cuda/lib64 -o test main.o test.o -lcudart 

tj umieścić bibliotekę ostatni w link. (W każdym razie muszę)

Powiązane problemy