Компиляция кода Cuda в Qt Creator на Windows

В течение нескольких дней я пытался запустить файл проекта Qt, работающий в 32-битной системе Windows 7, в которую я хочу / должен включить код Cuda. Эта комбинация вещей либо настолько проста, что никто никогда не удосужился подать пример в Интернете, либо настолько трудна, что никому не удавалось, кажется. Как бы то ни было, единственными полезными ветками форума, которые я обнаружил, была та же проблема в Linux или Mac или с Visual Studio в Windows.
Однако все они дают всевозможные ошибки, будь то из-за связывания или конфликтования библиотек, пробелов в именах файлов или несуществующих папок в версии Cuda SDK для Windows.
Есть ли кто-то, кто имеет четкое .pro файл, чтобы предложить, что делает трюк?

Я собираюсь скомпилировать простую программу с обычным кодом C ++ в стиле Qt, с библиотеками Qt 4.8, которые ссылаются на несколько модулей Cuda в файлах .cu. Что-то в форме:

TestCUDA \
TestCUDA.pro
main.cpp
test.cu

10

Решение

Так что мне наконец удалось собрать .pro файл, который работает на моем и, вероятно, на всех системах Windows. Ниже приведена простая тестовая программа, которая, вероятно, должна сработать. Ниже приведен небольшой файл проекта и тестовая программа, которая работает по крайней мере на моей системе.

Файловая система выглядит следующим образом:

TestCUDA \
TestCUDA.pro
main.cpp
vectorAddition.cu

Файл проекта гласит:

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

}

Обратите внимание QMAKE_LFLAGS_RELEASE = /NODEFAULTLIB:msvcrt.libМне потребовалось много времени, чтобы понять, но эта библиотека, кажется, конфликтует с другими вещами в Cuda, которая выдает странные предупреждения и ошибки связывания. Если у кого-то есть объяснение этому и, возможно, более красивый способ обойти это, я бы хотел услышать это.

Кроме того, поскольку пути к файлам Windows часто содержат пробелы (и SDK от NVIDIA по умолчанию также делают это), необходимо искусственно добавлять кавычки вокруг путей включения. Опять же, если кто-то знает более элегантный способ решения этой проблемы, мне было бы интересно узнать.

main.cpp файл выглядит так:

#include <cuda.h>
#include <builtin_types.h>
#include <drvapi_error_string.h>

#include <QtCore/QCoreApplication>
#include <QDebug>

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

Файл Cuda vectorAddition.cu, который описывает простое векторное сложение, выглядит так:

#include <cuda.h>
#include <builtin_types.h>

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<<<blocksPerGrid, threadsPerBlock>>>(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);
}

Если вы заставите это работать, то я думаю, что более сложные примеры самоочевидны.

Изменить (24-1-2013): Я добавил QMAKE_LFLAGS_DEBUG = /NODEFAULTLIB:msvcrtd.lib и CONFIG(debug) с дополнительным D_DEBUG флаг, так что он также компилируется в режиме отладки.

15

Другие решения

Используя msvc 2010, я обнаружил, что компоновщик не принимает параметр -l, однако nvcc нуждается в этом. Поэтому я сделал простое изменение в файле .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')

И команда nvcc (версия выпуска):

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 был вставлен вместо $$ LIBS.
Весь файл .pro, который работает для меня:

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
}

Я также добавил некоторые существенные объявления, то есть QT + = core для работы приложения, а также удалил часть SDK, что я не нашел полезным в этом случае.

1

Я попробовал эту комбинацию, чтобы работать. Не удалось заставить его работать из-за ряда зависимостей в
мой проект.
Мое окончательное решение состояло в том, чтобы разбить приложение на два отдельных приложения в Windows
1)

  1. Приложение CUDA, разработанное в VC и работающее как служба / DLL в Windows
  2. Графический интерфейс разработан в QT и использует DLL для задач, связанных с CUDA.

Надеюсь, это сэкономит время других

0
По вопросам рекламы [email protected]