函数声明
在GPU编程中,有三种函数的声明:
这里的host
端就是指CPU,device
端就是指GPU;使用__global__
声明的核函数是在CPU端调用,在GPU里执行;__device__
声明的函数调用和执行都在GPU中;__host__
声明的函数调用和执行都在CPU端。
__device__
和__host__
可作用于同一个函数,这样的话,这个函数既可以在主机端调用,也可以在设备端调用。
对于__global__
和__device__
函数,有几个需要注意的地方:
- 尽量少用递归
- 不要用静态变量(kernel不支持静态变量)
- 少用malloc
数据类型
基本数据类型
除了c中的数据类型外,cuda中还增加了一些数据类型:
- char[1-4], uchar[1-4]
- short[1-4], ushort[1-4]
- int[1-4], uint[1-4]
- long[1-4], ulong[1-4]
- longlong[1-4], ulonglong[1-4]
- float[1-4]
- double1, double2
向量数据类型
向量数据类型同时适用于host和device端,使用关键字make_<type name>
来构造,向量类型主要用来处理多维数据
int2 i2 = make_int2(1, 2);
float4 f4 = make_float4(1.0f, 2.0f, 3.0f, 4.0f);
使用.x
、.y
、.z
和.w
来索引:
int x = i2.x;
int y = i2.y;
float x = f4.x;
float y = f4.y;
float z = f4.z;
float w = f4.w;
数学函数
GPU主要用来做计算,常用的数学函数当然是必备的:
- 三角函数:sin, cos, tan, asin, acos, atan2等
- 指数函数:exp, log
- 进/舍位函数:trunc, ceil, floor
- 开根号函数:sqrt, rsqrt
cuda中还提供了一些内建的数学函数,比上面这些函数速度更快,但精度要低一些,适合于那种对精度要求不高,但运算速度要求比较高的场合,这些函数都以双下划线__
开头:__expf
、__logf
、__sinf
、__powf
等
并行优化定理
Amdahld定理,也就是相对串行程序而言,并行程序的加速率。程序可能的加速比取决于可以被并行化的部分。加速率的计算公式为:
其中P表示可并行化的比例,如果没有可以并行化的模块,则P=0,speedup=1;如果全部可以并行化,P=1,speedup为无穷大。
当有一半程序可以并行化时,P=50%,speedup=2.
GPU Hello World
Hello World
程序是我们学习任何编程语言时,第一个要完成的,虽然cuda c并不是一门新的语言,但我们还是从Hello World
开始Cuda编程。
#include <stdio.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
__global__ void hello_world(void)
{
printf("GPU: Hello world! Thread id : %dn", threadIdx.x);
}
int main(){
printf("CPU: Hello world!n");
hello_world <<<1, 10>>>();
// cudaDeviceReset must be called before exiting in order for profiling and
// tracing tools such as Nsight and Visual Profiler to show complete traces.
cudaDeviceReset();
return 0;
}
程序中的具体语法我们后面会讲到,这里只要记住<<<1, 10>>>
是调用了10个线程即可,执行上面的程序,会打印出10个GPU的Hello World
,这个就是SIMD,即单指令多线程,多个线程执行相同的指令,就像程序中的这个10个线程同时执行打印Hello Wolrd
的这个指令一样。