CUDA入门02:helloworld

本文介绍CUDA开发的第一步,按照惯例是输出一个hello world.

hello world

创建一个Qt C++程序,创建完成之后,默认工程中只有main.cpp文件。

将*.pro文件修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
TEMPLATE = app
INCLUDEPATH += . \
/opt/cuda/include

QT += core gui
CONFIG += debug

LIBS += -L"/opt/cuda/lib64" \
-lcudart \
-lcufft

OTHER_FILES += hello_world.cu

CUDA_SOURCES += hello_world.cu

CUDA_SDK = "/opt/cuda" # Path to cuda SDK install
CUDA_DIR = "/opt/cuda/" # Path to cuda toolkit install
SYSTEM_NAME = linux # Depending on your system either 'Win32', 'x64', or 'Win64'
SYSTEM_TYPE = 64 # '32' or '64', depending on your system
CUDA_ARCH = sm_80 # Type of CUDA architecture, for example 'compute_10', 'compute_11', 'sm_10'
NVCC_OPTIONS = --use_fast_math

INCLUDEPATH += $$CUDA_DIR/include
QMAKE_LIBDIR += $$CUDA_DIR/lib64/

CUDA_OBJECTS_DIR = ./

CUDA_LIBS = cudart cufft
CUDA_INC = $$join(INCLUDEPATH,'" -I"','-I"','"')
NVCC_LIBS = $$join(CUDA_LIBS,' -l','-l', '')

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 -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 $$NVCC_OPTIONS $$CUDA_INC $$NVCC_LIBS --machine $$SYSTEM_TYPE -arch=$$CUDA_ARCH -O3 -c -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
cuda.dependency_type = TYPE_C
QMAKE_EXTRA_COMPILERS += cuda
}

说明:

  • TEMPALTE表示这个程序是APP而不是多个子工程或者动态库
  • INCLUDEPATH/LIBS 是Qt工程用于添加头文件和库的
  • OTHER_FILES 表示将此文件以其他格式文件的方式添加到QT工程中,这样我们就可以在Qt Creator中编辑此文件
  • 然后将CUDA文件编译和Qt文件编译以混合编译的方式连起来,为了方便后续维护,一些参数以配置的方式实现

hello_world.cu内容为

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

__global__ void hello_world_kernel(){
printf("Hello World");
}

int main(){
hello_world_kernel<<<1,1>>>();
cudaDeviceSynchronize();
}

编译运行之后,在终端输出

1
Hello World

hello world2

上一个是简单的只有一个文件,本部分将其作为独立函数文件在main.cpp中调用

工程文件中不一样的是

1
2
3
4
5
6
7
HEADERS += hello.h

SOURCES += main.cpp

OTHER_FILES += hello.cu

CUDA_SOURCES += hello.cu

hello.h内容为

1
2
3
4
5
6
7
8
9
10
11
#ifndef HELLO_H
#define HELLO_H

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include "malloc.h"

void showhello(void);

#endif // HELLO_H

hello.cu内容为

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "hello.h"

extern "C"
__global__ void hellofromGPU(void)
{
printf("GPU:hello sunyi\n");
}

void showhello(void)
{
hellofromGPU <<<1,10>>>();
cudaDeviceSynchronize();
}

main.cpp内容为

1
2
3
4
5
6
#include<stdio.h>
#include "hello.h"
int main(void)
{
showhello();
}

编译运行结果为:

1
2
3
4
5
6
7
8
9
10
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi
GPU:hello sunyi

为什么是输出10条呢?

vectoradd

接下来我们看看CUDA提供的官方示例效果,将官方示例中的Samples/0_Introduction/vectorAdd/vectorAdd.cu偷过来,按照helloworld方式添加到工程中

运行输出为

1
2
3
4
5
6
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

将这些工程的配置部分拆解开来,作为以后开发使用的模板工程,这样就不用每次都配置了。

完整工程在CUDA_linux

模板工程还提供了Windows下CUDA的配置,但是需要安装对应的VS软件。

比如我现在使用的是最新版CUDA11.5依赖于VS2017/2019,当然使用Qt的也要安装对应的版本。我是使用在线安装器安装的5.14.2。