您现在的位置是:首页 >其他 >【C++】CUDA期末复习指南上(详细)网站首页其他

【C++】CUDA期末复习指南上(详细)

披星戴月的贾维斯 2024-06-09 12:00:02
简介【C++】CUDA期末复习指南上(详细)

? 博客主页:?@披星戴月的贾维斯
? 欢迎关注:?点赞?收藏?留言
?系列专栏:? C/C++专栏
?请不要相信胜利就像山坡上的蒲公英一样唾手可得,但是请相信,世界上总有一些美好值得我们全力以赴,哪怕粉身碎骨!?
?一起加油,去追寻、去成为更好的自己!

在这里插入图片描述

提示:以下是本篇文章正文内容,下面案例可供参考


前言

    现在也已经有很多学校陆陆续续进入到了考试月,想必不少同学和我一样在准备期末考,提前祝贺大家在期末考中都能取得自己满意的成绩,现在我和和大家一起分享一篇CUDA期末复习指南,希望对大家有帮助。

?1、早期的GPU编程

GPU图形处理器Graphics Processing Unit,是现在常用的设备。
提供一些基本的操作,对内存中的图像着色,显示在屏幕上。
GPU会处理一个复杂的多边形集合,即需要着色的图片映像,然后给这些多边形图上纹理,在进行光照和阴影处理。
一个重要的进步:可编程着色器programmable shader,GPU运行一些用来计算图片效果的小程序。GPU中的着色器就不是固定的,可以通过下载不同的着色器,来进行着色。这就是最初的通用图形处理器General Purpose Graphical Processor Unit, GPGPU。
GPU处理单元功能不再是固定的,CUDA是首次实现了可编程显卡,向程序员提供了一个真正通用的GPU编程语言。

GPU的基本架构以及与CPU的交互
在这里插入图片描述
解释:一个GPU内有许多流处理器簇(Streaming Multiprocessor,SM),类似CPU的核。
SM和共享存储(一级缓存)连接在一起,然后又与相当于SM间互联开关的二级缓存相连。
数据先是在主机的全局存储中,然后被主机取出并使用。主机将数据通过PCI-E互联开关直接送往GPU的存储空间。PCI-E互联开关的传输速度比任何一个互联网快很多。

流处理器SM内部组成结构图
在这里插入图片描述


?2、串行/并行问题 并发性 局部性

?并行程序标准

两个并行程序设计标准,OpenMP和MPI
线程模型比较适合OpenMP,进程模式适用于MPI。
在GPU环境下,就需要混合在一起。CUDA使用一个线程块(block)构成的网格(grid)。可以看成是一个进程(线程块)组成的队列(网格),进程间没有通讯。每个进程(线程块)内部有很多线程,这些线程以批处理的方式运行,成为线程束(warp)。

?并发性

首要内涵是,对于一个特定的问题,不考虑那种并行架构,只关注求解方法中哪些操作是可以并行执行的。

算法中可能会有一段不易并行的阶段,被称为瓶颈

CUDA将问题分解成线程块的网格,每块包含多个线程。块可以按照任意顺序执行,易并行问题,块容易按照任意顺序执行

线程网格(grid)->线程块(block)->线程(thread)
在这里插入图片描述

网格中的块可以被分配到任意一个有空闲槽的SM上。可以采用轮询调度策略,确保分配到每个SM上的块数基本相同。对于大部分内核程序而言,分块的数量应该是GPU中物理SM数量的八倍或者更多倍。

?局部性

计算性能的提高已经从受限于处理器运算吞吐率,发展到迁移数据成为首要限制因素。
局部性问题通过多级缓存来解决。当任务被多次重复执行,缓存作用会充分发挥。
工作基础是空间局部性和时间局部性。之前被访问过的数据很可能还要被再次访问(时间局部性);刚被访问过的数据附近的数据也很可能马上被访问到(空间局部性)。

脏数据指的是缓存中被程序修改过的数据。脏数据必须在新数据装入前写回到全局内存,也就是说如果需要全局内存访问,需要先把缓存中的数据写回到内存中,再访问内存数据。


?3、任务/数据并行

?任务并行

操作系统,多任务
操作系统,它实现的是一种任务并行的并行处理,各个进程是不同的、无关的。多个CPU核心运行不同的应用程序。
基于任务的并行适合于粗粒度的并行。
就GPU而言,粗粒度并行处理是由GPU卡和CPU内核程序来执行。GPU有两种方法来支持流水线并行处理模式。一是,若干个内核程序被一次排列成一个执行流,然后不同的执行流并发执行。二是,多个GPU协同工作,可以通过主机或者PCI-E总线,在不同GPU之间传递数据。

?数据并行:

关注数据及其所需的变换,不是待执行的任务
基于数据的并行适合于细粒度的并行。

弗林分类法

SIMD (Single Instruction Multiple Data)单指令多数据
MIMD (Multiple Instruction Multiple Data)多指令多数据
SISD (Single Instruction Single Data)单指令单数据
MISD (Multiple Instruction Single Data)多指令单数据

**常用的并行模式:
循环
派生/汇聚:先串行,然后遇到并行区,并行处理,然后再汇聚串行处理。采用数据的静态划分来实现常用于并发事件数量事先不确定的问题。遍历树形结构,路径搜索等。
分条/分块:绝大多数并行处理方法。比如:矩阵计算大气海洋模型
分而治之:把大问题分解称小问题
**

?4、GPU硬件结构

4.1?内存的分类

内存类型访问权限
全局内存可读可写
常量内存仅可读
纹理内存一般仅可读
寄存器内存可读可写
局部内存可读可写
共享内存可读可写

GPU有流处理器簇、流处理器。
GPU实际上是一个SM的阵列,每个SM包含N个核
一个GPU设备包含多个SM,这是GPU具有可扩展性的关键因素。
每个SM有一个寄存器文件,是能够以与SP相同速度工作的存储单元。不同型号GPU,寄存器文件大小不相同,用来存储SP上运行的线程内部活跃的寄存器。
每个SM内部访问的共享内存,是程序可控的高速缓存。与CPU内部的高速缓存不同,没有自动完成数据替换的硬件逻辑,完全由程序控制。

每个SM都设置有总线访问纹理内存、常量内存、全局内存。
纹理内存是针对全局内存的特殊视图,用来存储差值计算所需的数据
常量内存存储只读数据。

每个SM还有两个以上的专用单元(Special-Purpose Unit, SPU),SPU专门执行诸如正弦余弦函数/指数函数操作等特殊硬件指令。

内核函数:global void kernel<<<1, 1>>>();
__global__告诉编译器,这个函数可以在设备上运行的。
<<<一个线程块,每个线程块一个线程>>>
<<<gridDim, blockDim>>>(具体的函数传参)

cuda设备属性
在这里插入图片描述

?5、GPU与CPU差别

任务/数据并行:
GPU与CPU在缓存上的一个重要差别是缓存一致性”问题。
缓存一致性系统,一个内存写操作需要通知所有核的各个级别缓存,所有核看到的内存视图是一样的。随着核数量增多,通知的开销迅速增大,限制了一个处理器中的核数量不能太多。
非缓存一致系统,系统不会自动更新其他核的缓存。需要程序员写清楚每个处理器核输出的各自不同的目标区域。从程序角度,这支持一个核只负责一个输出或者一个小的输出集。
CPU一般缓存一致,GPU是非缓存一致的,因此GPU可以在一个芯片内有大量的核心。

GPU的方式,对于多数据的处理方式更灵活;CPU只能用指令集里固化的数据处理方式。


?6、GPU函数

  1. cudaMalloc:cudaMalloc 是CUDA中的一个函数,用于在设备端(GPU)分配一段内存空间。第一个参数是地址的二重指针,我们可以强制转换为(void**)类型的,第二个参数是申请的地址大小。
    举例:
HANDLE_ERROR( cudaMalloc( (void**) &dev_a, N * sizeof(int) ) );
  1. cudaMemcpy:cudaMemcpy 是 CUDA 中用于在主机(CPU)和设备(GPU)之间进行内存数据传输的函数。它的函数原型如下:
cudaError_t cudaMemcpy(
void *dst,
const void *src,
size_t count,
cudaMemcpyKind kind
);

dst 为目标内存地址,在数据传输过程中将接收数据; src 是源内存地址,数据将从这里传输到目标地址; count 是要传输的数据字节数; kind 是传输数据的方式。
cudaMemcpyHostToHost :从主机复制数据到主机;
cudaMemcpyHostToDevice :从主机复制数据到设备;
cudaMemcpyDeviceToHost :从设备复制数据到主机;
cudaMemcpyDeviceToDevice :从设备复制数据到设备。
举例:

HANDLE_ERROR( cudaMalloc( (void**) &dev_a, N * sizeof(int) ) );
  1. cudaFree
    cudaFree 是 CUDA 中用于释放设备(GPU)上已分配内存的函数。
    使用举例:
HANDLE_ERROR( cudaFree(dev_a ));
  1. cudaGetDeviceCount
    cudaGetDeviceCount 是 CUDA 中用于查询当前主机上可用 GPU 设备数量的函数。
    举例:
int deviceCount;
HANDLE_ERROR( cudaGetDeviceCount(&deviceCount) );
  1. cudaGetDeviceProperties
    cudaGetDeviceProperties 函数是CUDA提供的一种API,用于获取指定设备的属性信息。它的函数原型为
cudaError_t cudaGetDeviceProperties(
struct cudaDeviceProp* prop,
int device
);

其中, prop 是一个指向 cudaDeviceProp 结构体的指针,用于存储设备属性的详细信息。
device 表示要查询的设备的编号。请注意,在调用该函数之前,必须使用 cudaSetDevice 函数将要查询的设备设置为当前设备。
代码示例:

int main()
{
int deviceCount;
HANDLE_ERROR( cudaGetDeviceCount(&deviceCount) );
if (deviceCount == 0) {
printf("There is no available CUDA device.
");
return 0;
}
int dev = 0;
HANDLE_ERROR( cudaSetDevice(dev) );
cudaDeviceProp prop;
HANDLE_ERROR( cudaGetDeviceProperties(&prop, dev) );
printf("Device Name: %s
", prop.name);
printf("Total Global Memory: %ld bytes
", prop.totalGlobalMem);
printf("Number of Multi-Processors: %d
", prop.multiProcessorCount);
printf("Clock Rate: %d MHz
", prop.clockRate / 1000);
printf("Max Threads per Block: %d
", prop.maxThreadsPerBlock);
return 0;
}
  1. cudaMallocHost
    cudaMallocHost 是一种在主机上分配固定内存的 CUDA API 函数。
    使用方法:
int* host_data;
size_t size = 1024 * 1024 * sizeof(int); // 申请 1MB 内存
HANDLE_ERROR( cudaMallocHost(&host_data, size) );
cudaFreeHost(host_data);
  1. cudaFreeHost
    cudaFreeHost 函数用于释放由 cudaMallocHost 函数分配的主机内存空间。

?总结

    本文总共总结多个考点,都是很有可能被考到的,同学们可以收藏起来看,下期我们将会继续介绍cuda函数,以及几个可能会考编程题的重要编程题汇总,感谢大家的支持,一起进步!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。