Comstackndo el código de Cuda en Qt Creator en Windows

He intentado durante días obtener un archivo de proyecto Qt ejecutándose en un sistema Windows 7 de 32 bits, en el que quiero / necesito incluir el código Cuda. Esta combinación de cosas es tan simple que nadie se molestó en poner un ejemplo en línea, o tan difícil que nadie tuvo éxito, al parecer. De cualquier forma, los únicos hilos de foro útiles que encontré fueron el mismo problema en Linux o Mac, o con Visual Studio en Windows. Sin embargo, todos estos tipos dan toda clase de errores diferentes, ya sea debido a bibliotecas de vinculación o conflicto, o espacios en nombres de archivos o carpetas no existentes en la versión de Windows del SDK de Cuda. ¿Hay alguien que tenga un archivo .pro claro para ofrecer que haga el truco?

Mi objective es comstackr un progtwig simple con código ordinario de C ++ en estilo Qt, con bibliotecas Qt 4.8, que hacen referencia a varios módulos Cuda en archivos .cu. Algo de la forma:

 TestCUDA \ TestCUDA.pro main.cpp test.cu 

Así que finalmente logré ensamblar un archivo .pro que funciona en mi y probablemente en todos los sistemas de Windows. El siguiente es un progtwig de prueba fácil que probablemente debería ser el truco. El siguiente es un pequeño archivo de proyecto más un progtwig de prueba que funciona al menos en mi sistema.

El sistema de archivos se ve de la siguiente manera:

 TestCUDA \ TestCUDA.pro main.cpp vectorAddition.cu 

El archivo del proyecto dice:

 TARGET = TestCUDA # Define output directories DESTDIR = release OBJECTS_DIR = release/obj CUDA_OBJECTS_DIR = release/cuda # Source files SOURCES += src/main.cpp # This makes the .cu files appear in your project OTHER_FILES += vectorAddition.cu # CUDA settings <-- may change depending on your system CUDA_SOURCES += src/cuda/vectorAddition.cu CUDA_SDK = "C:/ProgramData/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/C" # Path to cuda SDK install CUDA_DIR = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v4.2" # Path to cuda toolkit install SYSTEM_NAME = Win32 # Depending on your system either 'Win32', 'x64', or 'Win64' SYSTEM_TYPE = 32 # '32' or '64', depending on your system CUDA_ARCH = sm_11 # Type of CUDA architecture, for example 'compute_10', 'compute_11', 'sm_10' NVCC_OPTIONS = --use_fast_math # include paths INCLUDEPATH += $$CUDA_DIR/include \ $$CUDA_SDK/common/inc/ \ $$CUDA_SDK/../shared/inc/ # library directories QMAKE_LIBDIR += $$CUDA_DIR/lib/$$SYSTEM_NAME \ $$CUDA_SDK/common/lib/$$SYSTEM_NAME \ $$CUDA_SDK/../shared/lib/$$SYSTEM_NAME # Add the necessary libraries LIBS += -lcuda -lcudart # The following library conflicts with something in Cuda QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.lib QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib # The following makes sure all path names (which often include spaces) are put between quotation marks CUDA_INC = $$join(INCLUDEPATH,'" -I"','-I"','"') # Configuration of the Cuda compiler CONFIG(debug, debug|release) { # Debug mode cuda_d.input = CUDA_SOURCES cuda_d.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o cuda_d.commands = $$CUDA_DIR/bin/nvcc.exe -D_DEBUG $$NVCC_OPTIONS $$CUDA_INC $$LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} cuda_d.dependency_type = TYPE_C QMAKE_EXTRA_COMPILERS += cuda_d } else { # Release mode cuda.input = CUDA_SOURCES cuda.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o cuda.commands = $$CUDA_DIR/bin/nvcc.exe $$NVCC_OPTIONS $$CUDA_INC $$LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} cuda.dependency_type = TYPE_C QMAKE_EXTRA_COMPILERS += cuda 

}

Tenga en cuenta el QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.lib : me tomó mucho tiempo descubrirlo, pero esta biblioteca parece chocar con otras cosas en Cuda, lo que produce advertencias y errores de enlaces extraños. Si alguien tiene una explicación para esto, y posiblemente una forma más bonita de evitar esto, me gustaría escucharlo.

Además, dado que las rutas de archivos de Windows a menudo incluyen espacios (y el SDK de NVIDIA también lo hace de forma predeterminada), es necesario agregar comillas de manera artificial en las rutas de inclusión. Nuevamente, si alguien conoce una forma más elegante de resolver este problema, me gustaría saberlo.

El archivo main.cpp ve así:

 #include  #include  #include  #include  #include  // Forward declare the function in the .cu file void vectorAddition(const float* a, const float* b, float* c, int n); void printArray(const float* a, const unsigned int n) { QString s = "("; unsigned int ii; for (ii = 0; ii < n - 1; ++ii) s.append(QString::number(a[ii])).append(", "); s.append(QString::number(a[ii])).append(")"); qDebug() << s; } int main(int argc, char* argv []) { QCoreApplication(argc, argv); int deviceCount = 0; int cudaDevice = 0; char cudaDeviceName [100]; unsigned int N = 50; float *a, *b, *c; cuInit(0); cuDeviceGetCount(&deviceCount); cuDeviceGet(&cudaDevice, 0); cuDeviceGetName(cudaDeviceName, 100, cudaDevice); qDebug() << "Number of devices: " << deviceCount; qDebug() << "Device name:" << cudaDeviceName; a = new float [N]; b = new float [N]; c = new float [N]; for (unsigned int ii = 0; ii < N; ++ii) { a[ii] = qrand(); b[ii] = qrand(); } // This is the function call in which the kernel is called vectorAddition(a, b, c, N); qDebug() << "input a:"; printArray(a, N); qDebug() << "input b:"; printArray(b, N); qDebug() << "output c:"; printArray(c, N); if (a) delete a; if (b) delete b; if (c) delete c; } 

El archivo Cuda vectorAddition.cu , que describe una adición vectorial simple, se ve así:

 #include  #include  extern "C" __global__ void vectorAdditionCUDA(const float* a, const float* b, float* c, int n) { int ii = blockDim.x * blockIdx.x + threadIdx.x; if (ii < n) c[ii] = a[ii] + b[ii]; } void vectorAddition(const float* a, const float* b, float* c, int n) { float *a_cuda, *b_cuda, *c_cuda; unsigned int nBytes = sizeof(float) * n; int threadsPerBlock = 256; int blocksPerGrid = (n + threadsPerBlock - 1) / threadsPerBlock; // allocate and copy memory into the device cudaMalloc((void **)& a_cuda, nBytes); cudaMalloc((void **)& b_cuda, nBytes); cudaMalloc((void **)& c_cuda, nBytes); cudaMemcpy(a_cuda, a, nBytes, cudaMemcpyHostToDevice); cudaMemcpy(b_cuda, b, nBytes, cudaMemcpyHostToDevice); vectorAdditionCUDA<<>>(a_cuda, b_cuda, c_cuda, n); // load the answer back into the host cudaMemcpy(c, c_cuda, nBytes, cudaMemcpyDeviceToHost); cudaFree(a_cuda); cudaFree(b_cuda); cudaFree(c_cuda); } 

Si logras que esto funcione, creo que los ejemplos más complicados son evidentes por sí mismos.

Editar (24-1-2013): QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib el QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib y el CONFIG(debug) con el indicador D_DEBUG adicional, de modo que también se comstack en modo de depuración.

Utilizando msvc 2010 encontré que el enlazador no acepta el parámetro -l, sin embargo nvcc lo necesita. Por lo tanto, hice un cambio simple en el archivo .pro:

 # Add the necessary libraries CUDA_LIBS = cuda cudart # The following makes sure all path names (which often include spaces) are put between quotation marks CUDA_INC = $$join(INCLUDEPATH,'" -I"','-I"','"') # LIBRARIES IN FORMAT NEEDED BY NVCC NVCC_LIBS = $$join(CUDA_LIBS,' -l','-l', '') # LIBRARIES IN FORMAT NEEDED BY VISUAL C++ LINKER LIBS += $$join(CUDA_LIBS,'.lib ', '', '.lib') 

Y el comando nvcc (versión de lanzamiento):

 cuda.commands = $$CUDA_DIR/bin/nvcc.exe $$NVCC_OPTIONS $$CUDA_INC $$NVCC_LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} 

Se insertó $$ NVCC_LIBS en lugar de $$ LIBS. El archivo completo .pro, que funciona para mí:

 QT += core QT -= gui TARGET = TestCUDA CONFIG += console CONFIG -= app_bundle TEMPLATE = app # Define output directories DESTDIR = release OBJECTS_DIR = release/obj CUDA_OBJECTS_DIR = release/cuda # Source files SOURCES += main.cpp # This makes the .cu files appear in your project OTHER_FILES += vectorAddition.cu # CUDA settings <-- may change depending on your system CUDA_SOURCES += vectorAddition.cu #CUDA_SDK = "C:/ProgramData/NVIDIA Corporation/NVIDIA GPU Computing SDK 4.2/C" # Path to cuda SDK install CUDA_DIR = "C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v5.0" # Path to cuda toolkit install SYSTEM_NAME = win32 # Depending on your system either 'Win32', 'x64', or 'Win64' SYSTEM_TYPE = 32 # '32' or '64', depending on your system CUDA_ARCH = sm_11 # Type of CUDA architecture, for example 'compute_10', 'compute_11', 'sm_10' NVCC_OPTIONS = --use_fast_math # include paths INCLUDEPATH += $$CUDA_DIR/include #$$CUDA_SDK/common/inc/ \ #$$CUDA_SDK/../shared/inc/ # library directories QMAKE_LIBDIR += $$CUDA_DIR/lib/$$SYSTEM_NAME #$$CUDA_SDK/common/lib/$$SYSTEM_NAME \ #$$CUDA_SDK/../shared/lib/$$SYSTEM_NAME # The following library conflicts with something in Cuda QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.lib QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib # Add the necessary libraries CUDA_LIBS = cuda cudart # The following makes sure all path names (which often include spaces) are put between quotation marks CUDA_INC = $$join(INCLUDEPATH,'" -I"','-I"','"') NVCC_LIBS = $$join(CUDA_LIBS,' -l','-l', '') LIBS += $$join(CUDA_LIBS,'.lib ', '', '.lib') # Configuration of the Cuda compiler CONFIG(debug, debug|release) { # Debug mode cuda_d.input = CUDA_SOURCES cuda_d.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o cuda_d.commands = $$CUDA_DIR/bin/nvcc.exe -D_DEBUG $$NVCC_OPTIONS $$CUDA_INC $$NVCC_LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} cuda_d.dependency_type = TYPE_C QMAKE_EXTRA_COMPILERS += cuda_d } else { # Release mode cuda.input = CUDA_SOURCES cuda.output = $$CUDA_OBJECTS_DIR/${QMAKE_FILE_BASE}_cuda.o cuda.commands = $$CUDA_DIR/bin/nvcc.exe $$NVCC_OPTIONS $$CUDA_INC $$NVCC_LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} cuda.dependency_type = TYPE_C QMAKE_EXTRA_COMPILERS += cuda } 

También agregué algunas declaraciones esenciales, es decir, QT + = core para que la aplicación funcione, y también eliminé la parte del SDK, que no encontré útil en este caso.

Intenté esta combinación para trabajar. No pude hacerlo funcionar debido a una serie de dependencias en mi proyecto. Mi última solución fue dividir la aplicación en dos aplicaciones separadas en Windows 1)

  1. Aplicación CUDA desarrollada en VC y ejecutándose como un servicio / DLL en Windows
  2. Interfaz GUI desarrollada en QT y usando el DLL para tareas relacionadas con CUDA.

Espero que ahorre tiempo a otros