Compilazione del codice Cuda in Qt Creator su Windows

Ho cercato per giorni di ottenere un file di progetto Qt in esecuzione su un sistema Windows 7 a 32 bit, nel quale voglio / devo includere il codice Cuda. Questa combinazione di cose è talmente semplice che nessuno si è mai preso la briga di mettere un esempio online, o così difficile che nessuno ci sia mai riuscito, a quanto pare. In ogni caso, gli unici thread utili del forum che ho trovato erano lo stesso problema su Linux o Mac, o con Visual Studio su Windows. Tuttavia, tutti questi errori danno errori di ogni tipo, a causa di librerie di collegamento o di conflitto, o spazi nei nomi di file o cartelle non esistenti nella versione di Windows dell’SDK CUDA. C’è qualcuno che ha un file .pro chiaro da offrire che faccia il trucco?

Sto cercando di compilare un semplice programma con codice C ++ ordinario in stile Qt, con librerie Qt 4.8, che fanno riferimento a diversi moduli Cuda in file .cu. Qualcosa nella forma:

 TestCUDA \ TestCUDA.pro main.cpp test.cu 

Così finalmente sono riuscito a assemblare un file .pro che funziona sul mio e probabilmente su tutti i sistemi Windows. Quello che segue è un programma di test facile che probabilmente dovrebbe fare il trucco. Quello che segue è un piccolo file di progetto più un programma di test che funziona almeno sul mio sistema.

Il file system ha il seguente aspetto:

 TestCUDA \ TestCUDA.pro main.cpp vectorAddition.cu 

Il file di progetto riporta:

 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 

}

Nota QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.lib : mi ci è voluto molto tempo per capire, ma questa libreria sembra scontrarsi con altre cose in Cuda, che produce strani avvisi e errori di collegamento. Se qualcuno ha una spiegazione per questo, e potenzialmente un modo più carino per aggirare questo, mi piacerebbe sentirlo.

Inoltre, poiché i percorsi dei file di Windows spesso includono spazi (e l'SDK di NVIDIA lo fa anche per impostazione predefinita), è necessario aggiungere artificialmente virgolette attorno ai percorsi di inclusione. Ancora una volta, se qualcuno conosce un modo più elegante per risolvere questo problema, sarei interessato a sapere.

Il file main.cpp il seguente aspetto:

 #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; } 

Il file Cuda vectorAddition.cu , che descrive un'aggiunta vettoriale semplice, assomiglia a questo:

 #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); } 

Se riesci a far funzionare tutto questo, allora gli esempi più complicati sono ovvi, penso.

Modifica (24-1-2013): Ho aggiunto il QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib e il CONFIG(debug) con il flag D_DEBUG aggiuntivo, in modo che D_DEBUG anche in modalità di debug.

Utilizzando msvc 2010 ho scoperto che il linker non accetta il parametro -l, tuttavia nvcc ne ha bisogno. Pertanto ho apportato una semplice modifica al file .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') 

E il comando nvcc (versione di rilascio):

 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} 

$$ NVCC_LIBS è stato inserito al posto di $$ LIBS. L’intero file .pro, che funziona per me:

 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 } 

Ho anche aggiunto alcune dichiarazioni essenziali, ovvero QT + = core per far funzionare l'app, e ho anche rimosso la parte SDK, che in questo caso non ho trovato utile.

Ho provato questa combinazione per funzionare. Imansible farlo funzionare a causa di un numero di dipendenze nel mio progetto. La mia soluzione finale era di rompere l’applicazione in due applicazioni separate su Windows 1)

  1. Applicazione CUDA sviluppata in VC e in esecuzione come servizio / DLL in Windows
  2. Interfaccia GUI sviluppata in QT e utilizzo della DLL per attività correlate a CUDA.

Spero che salvi un po ‘di tempo dagli altri