4.1 Cuda编程模型中的错误检测
可以查看Cuda error的四个函数:
-
cudaGetLastError(): 这个函数用来检测最近一次的cuda调用是否有错误。
-
cudaPeekAtLastError(): 同样是用来检测错误,但是不会清除错误标识。
-
cudaGetErrorString(): 这个函数用来将错误代码转换为字符串形式。
-
cudaGetErrorName(): 这个函数用于获取指定的错误码对应的错误名称。
通常情况下,在cuda程序的每个cuda调用后调用cudaGetLastError()函数,来检测是否有错误发生。如果有错误,则使用cudaGetErrorString()函数将错误代码转换为字符串形式,并使用打印语句将错误信息输出到控制台。
tip: cudaError_t cudaGetLastError(): 这个函数与cudaGetLastError()功能相同,但是它返回cudaError_t类型,允许您对错误进行进一步处理。
4.2 Cuda编程模型中的事件
Cuda编程模型中的事件。事件的本质就是一个标记,它与其所在的流内的特定点相关联。可以使用时间来执行以下两个基本任务:
同步流执行 和 监控设备的进展
流中的任意点都可以通过API插入事件以及查询事件完成的函数,只有事件所在流中其之前的操作都完成后才能触发事件完成。默认流中设置事件,那么其前面的所有操作都完成时,事件才出发完成。
事件就像一个个路标,其本身不执行什么功能,就像我们最原始测试c语言程序的时候插入的无数多个printf一样。
//声明:
cudaEvent_t event;
//创建:
cudaError_t cudaEventCreate(cudaEvent_t* event);
//销毁:
cudaError_t cudaEventDestroy(cudaEvent_t event);
//添加事件到当前执行流:
cudaError_t cudaEventRecord(cudaEvent_t event, cudaStream_t stream = 0);
//等待事件完成,设立flag:
cudaError_t cudaEventSynchronize(cudaEvent_t event);//阻塞
cudaError_t cudaEventQuery(cudaEvent_t event);//非阻塞
//记录执行的事件:
cudaError_t cudaEventElapsedTime(float* ms, cudaEvent_t start, cudaEvent_t stop);
4.3 Cuda编程模型中多种类型的存储单元
在Cuda编程中,通常会使用尽量小的存储单元,提高程序的性能。但是,这需要根据具体情况考虑到存储单元的速度和容量,以及数据的类型和使用方式。
-
Register:最快,但可用数量最少,适合存储短期需要的数据。
-
Shared Memory:比寄存器慢一些,可用数量更多,适合存储需要在线程之间共享的数据。
-
Local Memory: 速度略慢于Shared Memory,主要用于存储单线程内的数据。
-
Texture Memory: 用于存储图形和图像数据,速度比较快,也可以方便地进行纹理映射。
-
Constant Memory: 可以在程序执行过程中高效访问,但是不能修改,速度比Global Memory快。
-
Global Memory: 最慢的存储单元,不可以被直接访问,通常需要利用其他存储单元中转数据。
-
Host Memory: 存储在主机中,速度比Global Memory慢。
-
4.4 利用共享存储单元来加速矩阵乘法 (重点)
利用共享存储单元加速矩阵乘法的思路是,将一个矩阵分块,并将每一块的部分数据加载到共享存储单元中,以便在单个 CUDA 核心中重复访问多次。
具体的实现方式:
-
将矩阵分块:把矩阵分成多个小矩阵,每个小矩阵与每个 CUDA 核心对应。
-
加载数据到共享存储单元中:每个 CUDA 核心加载其对应的小矩阵中的数据到共享存储单元中。
-
计算:在共享存储单元中使用单个线程计算每个元素的结果。
-
同步:所有线程都完成后,需要同步以保证结果的正确性。
-
写入结果:将结果写回到全局存储单元中。
通过使用共享存储单元,可以减少对全局存储单元的访问,从而提高矩阵乘法的性能。
课后作业:
1. 修改BLOCK_SIZE查看性能变化
当BLOCK_SIZE增大时,一个block内的线程数量增多,因此需要更多的共享内存来存储数据。
这会影响共享内存的使用,并且如果共享内存使用量过多,可能导致性能下降。
因此,如果增加BLOCK_SIZE时共享内存使用量超过预期,可能导致性能变差。
反之,如果增加BLOCK_SIZE时共享内存使用量适当,则可能导致性能提高。
因此,修改BLOCK_SIZE需要适当调整以保证性能。