CUDA学习笔记
头文件
// CUDA runtime
#include <cuda_runtime.h>
// helper functions and utilities to work with CUDA
#include <helper_functions>
#include <helper_cuda.h>
checkCudaErrors()
CUDA examples中有checkCudaErrors(),这个是定义了一个宏,来确保函数API调用正确,这种方式会使编程更加的简介明了。
HIP中没有checkCudaErrors()对应的checkHipErrors(),可以在hip文件中这样自定义一个内联函数:
#define checkHipErrors( a ) do { \
if (hipSuccess != (a)) { \
fprintf(stderr, "Hip runtime error in line %d of file %s \
: %s \n", __LINE__, __FILE__, hipGetErrorString(hipGetLastError()) ); \
/*exit(EXIT_FAILURE);*/ \
} \
} while(0);
这样就可以直接把checkCudaErrors转换为checkHipErrors.
HANDLE_ERROR()
HANDLE_ERROR()是我们定义的一个宏,作为辅助代码的一部分。这个宏只是判断函数调用是否返回了一个错误值,如果是的话,那么将输出相应的错误消息,退出应用程序并将退出码设置为EXIT_FAILURE。
(代码参见common/book.h)
#ifndef __BOOK_H__
#define __BOOK_H__
#include <stdio.h>
static void HandleError( cudaError_t err,
const char *file,
int line ) {
if (err != cudaSuccess) {
printf( "%s in %s at line %d\n", cudaGetErrorString( err ),
file, line );
exit( EXIT_FAILURE );
}
}
#define HANDLE_ERROR( err ) (HandleError( err, __FILE__, __LINE__ ))
#define HANDLE_NULL( a ) {if (a == NULL) { \
printf( "Host memory failed in %s at line %d\n", \
__FILE__, __LINE__ ); \
exit( EXIT_FAILURE );}}
cudaMalloc()和cudaFree()
通过cudaMalloc()来分配内存:类似于标准的C函数malloc(),cudaMalloc()函数的作用是告诉CUDA运行时在设备上分配内存。cudaMalloc() 函数有两个参数:第一个参数是一个指针(指向用于保存新分配内存地址的变量);第二个参数是分配内存的大小。除了分配内存的指针不是作为函数的返回值外,这个函数的行为与malloc()是相同的,并且返回类型为void.
需要调用cudaFree()释放cudaMalloc()分配的内存*(这个函数的行为与free()的行为非常相似)。
cudaMemcpy()
在主机代码中可以通过调用cudaMemcpy()来访问设备上的内存。这个函数调用的行为类似于标准C中的memcpy(),只不过多了一个参数来指定设备内存指针究竟是源指针还是目标指针。
【注意】cudaMemcpy()的参数:
- cudaMemcpyDeviceToHost将告诉运行时源指针是一个设备指针,而目标指针是一个主机指针(本示例即是如此)
- cudaMemcpyHostToDevice将告诉运行时源指针是一个主机指针,而目标指针是一个设备指针。
- cudaMemcpyDeviceToDevice将告诉运行时两个指针都是位于设备上。
- 如果源指针和目标指针都位于主机上,那么可以直接调用标准C的 memcpy() 函数。
kernel <<< BlocksPerGrids,threadsPerBlocks >>>( 参数列表 )
尖括号中,两个参数分别表示每个Grids中的并行Blocks数目和每个Blocks中的线程数目。
例如。如果指定的是kernel<<<2,1>>>(),那么可以认为运行时将创建核函数的.两个副本,并以并行的方式运行它们。我们将每个并行执行环境都称为一个线程块(Block)。如果指定的kernel<<<256,1>>>(),那么将有256个线程块在GPU上运行。
(N + dimBlock.x - 1) / dimBlock.x
用(N + dimBlock.x - 1) / dimBlock.x表示block的维度,是为了保证block的数量是一个整数,并且整个grid中的thread数量比实际处理的元素数量要多。这样做的两一个好处是:一个grid中的block数量只与问题规模有关,而与实际硬件设备中拥有多少个处理核心没关系。