Estoy intentando separar un programa CUDA en dos archivos .cu separados en un esfuerzo por acercarme a escribir una aplicación real en C++. Tengo un pequeño programa simple que:Cómo separar el código CUDA en varios archivos
Asigna una memoria en el host y el dispositivo.
Inicializa la matriz de host en una serie de números. copias del conjunto anfitrión de una serie de dispositivos de encuentra la plaza de todos los elementos de la matriz usando un kernel dispositivo copias del array dispositivo de nuevo a la matriz huésped imprime los resultados
Esto funciona muy bien si pongo todo en un archivo .cu y ejecútelo. Cuando lo divido en dos archivos separados, empiezo a recibir errores de enlace. Al igual que todas mis preguntas recientes, sé que esto es algo pequeño, pero ¿qué es?
KernelSupport.cu
#ifndef _KERNEL_SUPPORT_
#define _KERNEL_SUPPORT_
#include <iostream>
#include <MyKernel.cu>
int main(int argc, char** argv)
{
int* hostArray;
int* deviceArray;
const int arrayLength = 16;
const unsigned int memSize = sizeof(int) * arrayLength;
hostArray = (int*)malloc(memSize);
cudaMalloc((void**) &deviceArray, memSize);
std::cout << "Before device\n";
for(int i=0;i<arrayLength;i++)
{
hostArray[i] = i+1;
std::cout << hostArray[i] << "\n";
}
std::cout << "\n";
cudaMemcpy(deviceArray, hostArray, memSize, cudaMemcpyHostToDevice);
TestDevice <<< 4, 4 >>> (deviceArray);
cudaMemcpy(hostArray, deviceArray, memSize, cudaMemcpyDeviceToHost);
std::cout << "After device\n";
for(int i=0;i<arrayLength;i++)
{
std::cout << hostArray[i] << "\n";
}
cudaFree(deviceArray);
free(hostArray);
std::cout << "Done\n";
}
#endif
MyKernel.cu
#ifndef _MY_KERNEL_
#define _MY_KERNEL_
__global__ void TestDevice(int *deviceArray)
{
int idx = blockIdx.x*blockDim.x + threadIdx.x;
deviceArray[idx] = deviceArray[idx]*deviceArray[idx];
}
#endif
Build Log:
1>------ Build started: Project: CUDASandbox, Configuration: Debug x64 ------
1>Compiling with CUDA Build Rule...
1>"C:\CUDA\bin64\nvcc.exe" -arch sm_10 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin" -Xcompiler "/EHsc /W3 /nologo /O2 /Zi /MT " -maxrregcount=32 --compile -o "x64\Debug\KernelSupport.cu.obj" "d:\Stuff\Programming\Visual Studio 2008\Projects\CUDASandbox\CUDASandbox\KernelSupport.cu"
1>KernelSupport.cu
1>tmpxft_000016f4_00000000-3_KernelSupport.cudafe1.gpu
1>tmpxft_000016f4_00000000-8_KernelSupport.cudafe2.gpu
1>tmpxft_000016f4_00000000-3_KernelSupport.cudafe1.cpp
1>tmpxft_000016f4_00000000-12_KernelSupport.ii
1>Linking...
1>KernelSupport.cu.obj : error LNK2005: __device_stub__Z10TestDevicePi already defined in MyKernel.cu.obj
1>KernelSupport.cu.obj : error LNK2005: "void __cdecl TestDevice__entry(int *)" ([email protected]@[email protected]) already defined in MyKernel.cu.obj
1>D:\Stuff\Programming\Visual Studio 2008\Projects\CUDASandbox\x64\Debug\CUDASandbox.exe : fatal error LNK1169: one or more multiply defined symbols found
1>Build log was saved at "file://d:\Stuff\Programming\Visual Studio 2008\Projects\CUDASandbox\CUDASandbox\x64\Debug\BuildLog.htm"
1>CUDASandbox - 3 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Me postulo Visual Studio 2008 en Windows 7 de 64 bits.
Editar:
creo que es necesario dar más detalles sobre esto un poco. El resultado final que estoy buscando aquí es tener una aplicación normal de C++ con algo así como Main.cpp con el evento int main()
y ejecutar las cosas desde allí. En ciertos puntos de mi código .cpp, quiero poder hacer referencia a los bits de CUDA. Así que mi forma de pensar (y corregirme si hay una convención más estándar aquí) es que incluiré el código Kernel de CUDA en sus archivos .cu y luego tendré un archivo .cu de soporte que se encargará de hablar con el dispositivo y llamar funciones del núcleo y qué no.
Sírvanse explicar con un ejemplo sencillo código –
Su MyKernel.h debe tener 'TestDeviceWrapper vacío (DIM3 rejilla, bloque DIM3, int * devicearray)' ya que cuando el KernelSupport.cu convierte KernelSupport.cpp cl.exe no va a entender la __global__ sintaxis. Luego, en MyKernel.cu, 'TestDeviceWrapper()' solo llama a 'TestDevice <<<> >>'. – Tom
Eso suena razonable, el código proporcionado supone que se incluirá en un archivo cuda, como se muestra en la pregunta. –