贡献者: addis
cuda-c-basics.pdf
__global__
就可以定义为在 GPU 中执行的函数(device code). 在 CPU 中执行的叫做 host code.
fun<<<m,n>>>()
.
cudaMalloc();
用于在 GPU 中分配空间
nvprof ./<exename>
可用于测试程序的用时情况(profiling)
.cu
后缀,否则会报错(包括 include 的头文件中的 cuda 语法)!
cudaGetDeviceCount(int *deviceCount)
可以返回 GPU 的数量。
cudaSetDevice(int device)
用于切换 GPU, 其中 device 是 GPU 的编号,从 0 开始。默认的 GPU 编号是 0.
cudaGetDeviceProperties(struct cudaDeviceProp * prop, int device)
可以获取 GPU 信息。prop 中常用的 member 如下:
prop.name
是 GPU 型号(名称), prop.major
是 capability 的编号,每个编号是一种构架,3: Kepler, 5: Maxwell, 6: Pascal, 7: Volta, prop.minor 是 capability 的小数点后的编号,prop.multiProcessorCount
是 multiprocessor 的数量,总核数等于该数量乘以每个 mp 中的核数(与构架有关), prop.deviceOverlap
表示 GPU 是否有同时执行 kernel 和传数据的能力,只有这个能力存在,用多个 stream 才有可能加速。
prop.totalGlobalMem
和 prop.totalConstMem
分别是 GPU 内存的大小和 const 空间的大小。prop.canMapHostMemory
决定 GPU 是否能使用 zero-copy memory. 剩下的见 cudaDeviceProp 的定义。
cuda*()
函数都会返回错误类型 cudaError_t
, cudaGetErrorString(cudaError_t err)
可以返回错误的描述。
cudaDeviceSynchronize()
函数在使 host 程序等待所有 device 完成任务。
__syncthreads()
函数在 kernel 中的所有 thread 同步。
__constant__
) 变量既可以在 host code 中也可以在 device code 中使用。
__device__
, 则该 global 变量只能用于 device code, 不能在 host 中使用,但可以在 host 中用 cudaMemcpyToSymbol()
对其赋值。如果改用 __cnstant__
, 则只能在 device code 中读取该变量,但同样可以在 host 中用 cudaMemcpyToSymbol()
. __constant__
空间一般只有 64kb, 但有可能将速度变快(见 cuda by examples).
__device__
, __constant__
, 支持特定的 class object, 这个 class 必须要有一个空的 constructor 或者没有 constructor (默认).
__device__
, 如果要在 kernel 和 host 中执行,前面要加 __host__ __device__
.
new
和 delete
的,也可用 malloc()
和 free()
! 使用的是 device 空间的储存,在一块专门的区域叫做 heap. 如果不够的话,new
会返回 nullptr
.(貌似不一定!)
cudaDeviceGetLimit(size_t* size, cudaLimitMallocHeapSize) // 获取 heap size
cudaDeviceSetLimit(cudaLimitMallocHeapSize, size_t size) // 设置 heap size
new
,貌似消耗的 heap 空间会随 block 数量不断增长,而不是与 cuda core 的数量成正比。而且 heap 不够的时候不会报错,而是整个 kernel 都不执行。
cudaMalloc()
代替 new, 速度要快许多, 然而 Quadro P5000 反而会慢,但是慢的不多。
#include "cuda_complex.h"
, 见我的 CUDATest/template.
cudaEven_t start, stop;
cudaEventCreate(&start); cudaEventCreate(&stop);
cudaEventRecord(start, 0);
// do some work on the GPU
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop); // let CPU wait for the event to finish
cudaEventElapsedtime(&elapsedTime, start, stop); // time unit is "ms"
cudaEventDestroy(start); cudaEventDestroy(stop);
malloc()
分配 pageable host memory, 而 cudaHostAlloc(void** pointer, size_t size, cudaHostAllocDefault)
分配 page-locked host memory (或 pinned memory). 后者不会被 swap 到硬盘中。要释放后者分配的内存,用 cudaFreeHost(void * pointer)
即可。page-locked 内存在 CPU 和 GPU 间的传输速度大概是 pageable 内存的两倍。
cudaHostAlloc(void** pointer, size_t size, cudaHostAllocMapped)
, 分配出来的内存就是 zero-copy memory, 因为这种内存可以直接在 kernel code 中读取。
cudaSetDeviceFlags(cudaDeviceMapHost)
.
cudaHostAllocMapped | cudaHostAllocWriteCombined
可以提升性能。
cudaHostGetDevicePointer(void **pDevice, void *pHost, 0)
函数用于将 zero-copy memory 从 Host 中的指针得到 Device 的指针。
cudaThreadSynchronize()
即可恢复。
cudaMallocManaged(void **pointer, size_t size);
cudaFree(void *pointer);
cuda-gdb name.x
-g
和 -G
. 其中 -g
是 CPU 调试,-G
是 GPU 调试。
cuda block <number> tread <number>
或者 cuda block (1,2,3) tread (4,5,6)
指定三维线程。
cuda block <number>
和 cuda thread <number>
.
cuda block thread
info cuda devices
info cuda kernels
#ifdef _MSC_VER
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#endif
#include <iostream>
using namespace std;
__global__
void add1(int *x, int thread) { x[thread] += 1; }
int main()
{
int i, N = 3;
int *x, *dev_x;
cudaSetDevice(0);
cudaSetDeviceFlags(cudaDeviceMapHost);
cudaHostAlloc((void**)&x, N*sizeof(int),
cudaHostAllocWriteCombined | cudaHostAllocPortable |
cudaHostAllocMapped);
for (i = 0; i < N; ++i)
x[i] = i;
cudaHostGetDevicePointer(&dev_x, x, 0);
#pragma omp parallel for
for (i = 0; i < N; ++i) {
if (i != 0) {
cudaSetDevice(i);
cudaSetDeviceFlags(cudaDeviceMapHost);
}
add1<<<1,1>>>(dev_x, i);
cudaThreadSynchronize();
}
cout << "the result is: " << x[0] << " " << x[1]
<< " " << x[2] << endl;
}