cuda必须装在c盘吗_总体流程设计(1)-CUDA程序的等级结构

本文详细介绍了CUDA程序的等级结构,从Thread、Warp、Block到Grid,阐述了每一层的功能和意义。CUDA的等级结构使得GPU能高效执行并行任务,其中Thread是基本任务单元,Warp是同步运行的最小单元,Block提供了资源共享和同步能力,Grid则是整体任务的组织形式。此外,文中还提到了CUDA的Dynamic Parallelism和Cooperative Groups等特性,为更灵活的并行编程提供了可能。
摘要由CSDN通过智能技术生成

上次聊了聊CUDA程序的性能优化思路,发现写起来真是停不下来……因为换了工作,后续就拖了挺久。现代人真的挺忙的,长文章意义有限,我懒得写,大家也懒得看。想了想,先把一些系统的东西讲讲清楚,然后讲些琐碎的感想,每次就讲一两个要点,理论少点,随性些,不拘于格式,多举点具体例子,也许效果更好些。不过这一次,好吧,长文预警……

顺便还是强调一下,这些知识还是有些门槛的,对刚入门的初学者可能不太友好。但只要你有些基础知识,看完后如果有不清楚的地方,可以自己找找资料深入研究,也许可以增加一些可能并不怎么有用的知识。我也会尽量多给出一些参考材料。有些地方我可能也会有一些想当然的地方,也希望大家能批评指正,共同学习。

今天开始,准备花几篇文章聊聊CUDA的总体流程设计。这是第一部分,主要讲CUDA程序的等级结构。

我这里说的总体流程设计,指的是怎么把一个具体任务转化为Kernel,Kernel每个thread和block之间应该怎么组合。如果一个kernel做不成,那多个Kernel怎么分工。这里的流程也包括Kernel之间,Kernel和其他API(比如cudaMemcpy),或者是和其他CPU任务之间,怎么配合等等。想对CUDA程序做一个很好的规划,就要先深入了解CUDA程序的各级组成单元。只有了解每层单元具体是怎么工作的,清楚它们相互同步、通信的机制,才能更好的让它们协作配合。所以这篇先讲CUDA程序的等级结构。

Kernel 上层的等级结构

首先简单阐述一下CUDA kernel以上的等级结构。每个CUDA程序都必须是一个CPU进程,其中可能包括一个到多个CPU线程,CPU线程间的共享关系与普通多线程程序是一样的。每个CUDA程序都包含(或隐含)一个到多个CUDA context(driver api里的CUcontext)。CUDA context可以看成是类似CPU进程的GPU进程,大部分的runtime api,包括memcpy,启动kernel,bind texture等等,都会运行在这个context上。每个context都有自己的资源空间,相互隔离,互不影响,所以有一个出错也不会影响到其他context。每个CUDA程序至少会有一个context,不显式初始化的话程序会自动分配一个,这也是runtime api大部分时候的用法。也可以申请多个,但每线程当前只能用一个。CUDA会维护一个context的栈,可以通过类似push/pop的方式切换当前context。每个context会包含一些模块(CUmodule,有的是以cubin文件形式保存),类似dll。模块内会有一些kernel function(CUfunction),也会有一些模块内资源的描述(比如constant memory,texture reference等),load模块时这些资源就会得到分配。值得一提的是,kernel function不仅可以访问本模块内的资源,其实整个context的内容都是可见的。更具体的描述可以参考CUDA C++ Programming Guide中driver api的部分。具体的driver api的内容也可以看CUDA Driver API.

这里有几个微妙的地方:

  • 一是多线程的CPU程序能共享context吗?答案是可以。其实本身同一进程的资源就是相互可见的,所以多线程可以共享context。每个context执行时有一个或多个stream,同一个stream内的api是序列化的,前一个返回后才能运行后一个。所以其实多线程并不适合同时操作同一个stream,但不同stream其实是可以同时操作的。一些更大型的应用也可以让每个线程维护自己的context,这样相互干扰更少,万一一个出错也不会导致整个进程崩溃。当然,CPU同时执行api是一回事,到了GPU设备端肯定还是有一个queue来维护顺序执行关系(比如申请资源这种肯定要排队,不可能完全并行)。
  • 二是多GPU的情况怎么办?其实每个卡(或者更精确的说是每个GPU芯片,对应driver api里的CUdevice)都有相互独立的context。资源也是相互独立的。CUDA里有managed memory,可以让它看起来是每个device都可访问(也包括host),但其实只是把数据搬运自动化后隐藏起来而已,本质上每个卡的资源还是分开的。CUDA程序暂时还不能做到自动把多块卡当成一块来用,一个kernel也不能自动分在两个GPU上运行,有NVlink也不行。所以当前情况下多GPU还是需要用户自己来手动分割任务。

Kernel的等级结构

一个CUDA Kernel大概可以分为这么几层(从底层到顶层):thread,warp,block,grid。下面就分别讲讲这几层的特征和运行模式。

1. Thread

Thread是CUDA程序的底层任务单元,与CPU的thread具有比较高的相似性(其实独立性上更像进程一些)。每个Thread都有一些私有资源:

  • General Perpose Register: 通用寄存器,简称GPR,有时也直接叫Register寄存器)。GPR通常按个算,一个是32bit,在CUDA的SASS汇编里一般写成R0R123这种格式。每个线程使用的具体GPR数目是编译器根据需要进行配置的,每个kernel的所有线程都保有相同数目的GPR。最近几代架构单线程最大可用数目是255,因为指令集里GPR编码有8bit(2^8=256),而且R255=RZ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值