浅谈GPGPU任务调度-1

2023-09-21 16:34:14

前言

转自 GPU and Computing 公众号

在先前的文章中《近距离看GPU计算(2)》我们介绍了GPU SM单元以Thread Block为单位的调度方法,这些的Block属于同一个kernel任务,当然处于相同的进程上下文(CUDA Context),针对的是任务内线程级别并行执行。我们知道现代GPU计算能力与日俱增,不断挑战新高。随之而来的问题是,单凭一个Kernel任务很能占满GPU,来自相同进程,甚至不同的进程的任务在时间上、空间上如何共享GPU,又是如何调度的呢?笔者曾经就这些问题求教于GPU公司专门的同事,给出的解释往往含混不清,很难有确定的答案。这里笔者不是自不量力要祭出终极大杀器,而是就一些文献浅见,尝试梳理下思路提出问题,望有识见的朋友能给与指正。主题内容大概分三个部分,第一部分我们讨论来自同一进程的任务的调度,第二部分会涉及来自不同进程上下文的任务如何共享GPU以及可能抢占的行为,第三部分会谈下GPU驱动框架对调度行为的一些支持。第一二部分主要讨论硬件的行为,第三部分从软件的视角分析。本文为其中第一部分。


1.Stream的概念

在正式开始介绍之前,我们先回顾下CUDA框架跟任务调度关系密切的stream的概念。Stream表示一个GPU任务队列,该队列中的任务将按照添加到Stream中的顺序先后而依次执行。所有的CUDA任务(包括kernel运行和数据搬运)都显式或隐式通过stream得到执行,stream也就两种类型,分别是:默认stream(defaut stream, 或者说stream 0)和其它stream。CUDA任务没有显式的指定stream就运行在默认stream上。stream任务的执行遵守下面规则。
不管是默认stream还是其它stream,每个stream里面的任务都按顺序执行。
来自其它不同stream的任务可以并发或者交错执行。
默认stream和其它stream之间互相同步,不能够同时执行。必须等到对方stream执行完毕。
以下代码表示如何创建使用默认stream和其它stream 的情形。

在这里插入图片描述

凡规则必有例外,在目前版本的Cuda通过nvcc选项–default-stream,可以使得CPU线程采用的默认stream跟其它stream一般无二。另外创建其它stream的时候可以通过传递cudaStreamNonBlocking标记告诉runtime该stream和默认stream不会互相隐式阻塞。为方便起见,接下来的讨论我们不涉及上述两种情形。

在这里插入图片描述

如果考虑stream,CUDA任务运行调度过程如图1所示,应用程序的各种任务分发到不同的stream上,按任务分发时的thread block大小定义再由硬件层次上的thread block调度器以thread block为单位分配给不同的SM运行,在SM内部,thread block由warp组成,warp为最小的执行调度单位,thread block->warp阶段的调度过程我们前面的文章已经涉及,这里不再赘述,在本文中,我们主要关注的是stream->thread block阶段的调度,另外因为暂且不考虑跨进程上下文,所以图示中stream S0…Si都来自同一个应用程序。

1.文献1的工作

在这小节里,我们介绍一下文献《GPU Scheduling on the NVIDIA TX2: Hidden Details Revealed》的工作。目前车载平台也大量利用GPU来加速绘制和计算工作,有些应用在关键路径上有实时的要求,比如里程计的绘制和障碍物检测等等,但是GPU内部任务如何调度一直是个黑盒子,各个GPU厂商都讳莫如深,更别提有公开文档记录了,这给实时任务的执行预测带来了困难,也影响相关产品的安全认证。基于此出现了一些通过Microbench或者反向工程来了解GPU调度行为的工作,下面涉及的文献就是其中一些例子。
在这里插入图片描述
文献1做了很多microbench的工作,来推测CUDA GPU任务调度的行为,并试图扩展到不同系列的GPU硬件。该文预设整个CUDA平台存有以下硬件队列,(a)对应硬件Copy Engine(以下简称CE)FIFO队列,CE负责在Host和GPU设备之间搬运数据,(b)对应硬件Kernel Execution Engine(以下简称EE)的FIFO队列,EE负责Kernel的执行。另外每个CUDA stream分别对应一个软件意义上的FIFO队列。这些队列的整体层次如图2所示。
在这里插入图片描述
根据microbench的结果,文献1总结了如下GPU任务调度规则,并在文献2中进一步验证,这些规则也适用于Nvidia Maxwell、Pascal、Volta系列GPU。而对较老Kepler版本,规则G2需要变更为当kernel到达其stream队列头部的时候, 它会被排入EE队列并从stream队列出列。
在这里插入图片描述
文献1的工作基于NVIDIA TX2平台,配置的GPU是Pascal版本,一共有两个SM,每个SM的硬件资源如下表。
在这里插入图片描述

根据以下kernel的分发序列和其对应的的资源要求,我们有了图3的调度结果。有心的读者不妨对照规则列表以及上表SM的资源能力推敲下,比如分别来自stream2和stream3的k4以及k5,按照其它条件,应该可以差不多同时刻得到执行,但是因为每个SM的shared memory大小限制,只能满足一个kernel的运行。

在这里插入图片描述
在这里插入图片描述

从Maxwell版本硬件开始,CUDA提供接口函数cudaStreamCreateWithPriority,使得创建stream的时候我们可以指定其优先级。文献1也考虑到了这种情况,认为调度硬件除普通EE队列,还有一个容纳高优先级任务的EE队列,并定义了如下额外规则来匹配,

kernel只能排入跟其优先级对应的EE队列。
普通EE队列的kernel只有在高优先级EE队列为空的时候才能得到分配执行。所以高优先级任务可以抢占普通优先级任务,抢占的粒度是thread block。另外这个规则也可以避免因资源限制导致优先级反转的情况。

2.Hyper-Q的改进

文献1有个较大的硬伤,其立论的基础是调度硬件只有一个EE队列,但是其试验的平台是TX2,配置有Pascal版本的GPU,按道理应该能支持Hyper-Q,也就是存在多个独立的EE队列,不知道是不是为简化起见,文章作者没有考虑Hyper-Q的因素。之前Fermi版本GPU在支持多个stream的时候,它们会被导入到同一个硬件队列,由于同一stream内任务的依赖关系,本来不需要同步的stream之间的任务不能真正同时运行,如下图所示,只有不同stream边界处的任务X和R,以及P和C才能并发执行。
在这里插入图片描述
另外一个显而易见的问题是不同的任务分发顺序会影响GPU执行的并发水平。如下图所示,假设stream1有ka1和kb1两个任务,stream2有ka2和kb2两个任务,以深度优先和广度优先发送任务其调度有截然不同的行为。
在这里插入图片描述

为克服这些问题,减轻CUDA程序并发优化的负担,Kepler版本GPU引入了Hyper-Q特性,使得可利用的硬件队列达到32个,每个stream都有对应的硬件工作队列,只要资源条件允许,可以实现不相关任务的充分并发。
在这里插入图片描述
那么当有多个硬件队列的时候,调度硬件实际上又是如何运作的呢?文献3提供了一些线索,我们这里提下,可以结合文献1验证过的现象一起来琢磨。应用程序的stream们会映射到硬件队列,这些映射信息会组织成一个runlist,每个硬件队列根据interleaving level在其中占据一个或多个slot,映射信息包括stream对应的Command Push Buffer以及时间片或者抢占策略等其它调度辅助信息。调度硬件会round robin扫描这个runlist,查看slot对应的command buffer有没有任务需要执行,如果这个slot被标记为不可抢占,就会等队列任务执行完成,否则时间片一过,当前的任务队列会被抢占,而切换到下个slot,等到再次运转到该任务队列的slot时候再恢复执行。抢占的粒度跟GPU硬件能力有关系,可能是block或者thread甚至是instruction级别,不一定跟时间片完全吻合。Interleaving level设置使得高优先级的stream有更多机会被执行到,如下图优先级高的stream在runlist可以有更多slot。
在这里插入图片描述

文献4来自AMD,探讨了HSA Queue或者说stream的数目超过硬件队列时如何处理,也可以一并参考下,这里就不再展开。

再补个后记,因前段时间个人工作有调整,有了个偷懒的理由,一晃大半年时间没有正式的更新了。本来准备春节假期写就的文章,也拖到二月份最后一天才发出来,不过还好还是在农历正月里,但愿是个好的开始,后面计划的内容不要烂尾。也希望关注的朋友们能多提宝贵建议,共同切磋。

主要参考资料:

GPU Scheduling on the NVIDIA TX2: Hidden Details Revealed
Scaling Up: The Validation of Empirically Derived Scheduling Rules on NVIDIA GPUs
Deadline-based Scheduling for GPU with Preemption Support
Oversubscribed Command Queues in GPUs
Kepler GK110/210 GPU Computing Architecture
CUDA C/C++ Streams and Concurrency

更多推荐

uniappAndroid平台签名证书(.keystore)生成

一、安装JRE环境https://www.oracle.com/java/technologies/downloads/#java8记住下载默认安装地址。ps:我都默认安装地址C:\ProgramFiles\Java\jdk-1.8二、安装成功后配置环境变量系统变量配置AVA_HOME放到环境变量去%JAVA_HOME

nginx部署多个项目

前言实现在一台服务器上使用nginx部署多个项目的方法查看并修改nginx安装的默认配置文件在Linux操作系统中,Nginx在编译安装时默认的配置文件路径是/usr/local/nginx/conf/nginx.conf。如果是通过发行版的包管理器安装,则默认的配置文件路径可能会相应改变,例如在Ubuntu下为/et

Vue中使用VueAMap

npm安装npminstallvue-amap--save注册:高德地图//在main.js中注册:高德地图importVueAMapfrom"vue-amap";Vue.use(VueAMap);VueAMap.initAMapApiLoader({key:"你的高德key",plugin:["AMap.AutoCo

【K8S系列】深入解析k8s网络插件—Flannel

序言做一件事并不难,难的是在于坚持。坚持一下也不难,难的是坚持到底。文章标记颜色说明:黄色:重要标题红色:用来标记结论绿色:用来标记论点蓝色:用来标记论点Kubernetes(k8s)是一个容器编排平台,允许在容器中运行应用程序和服务。今天学习一下k8s网络插件相关知识希望这篇文章能让你不仅有一定的收获,而且可以愉快的

C++ 类(1)

你知道吗,C++类是编程世界中的一种强大工具,它可以帮助我们更好地组织和管理代码。接下来,我将为你呈现一篇近万字的C++类的教程,希望能帮助你熟悉这个概念。首先,让我们从C++类的定义开始。类是一个模板,它描述了一种具有相同属性和行为的数据类型。听起来很复杂吗?别担心,我来给你举个例子。假设我们要创建一个名为"Car"

PostgreSQL 技术内幕(十)WAL log 模块基本原理

事务日志是数据库的重要组成部分,记录了数据库系统中所有更改和操作的历史信息。WALlog(WriteAheadLogging)也被称为xlog,是事务日志的一种,也是关系数据库系统中用于保证数据一致性和事务完整性的一系列技术,在数据库恢复、高可用、流复制、逻辑复制等模块中扮演着极其重要的角色。在这次直播中,我们为大家介

【8B10B编解码及verilog(xilinx example)解析】

8B10B编解码及verilog(xilinxexample)解析编码查表算法解码代码解析极性控制字K码编码8b/10b编码将串行的数据以8bit为一个单位进行编码处理得到一个10bit的数据,具体怎么操作呢,假设原始8位数据从高到低用HGFEDCBA表示,将8位数据分成高3位HGF和低5位EDCBA两个子组。经过5B

成都直播基地火热招商中,天府蜂巢成都直播基地招商政策汇总

随着直播产业的发展,四川天府新区也在逐步形成成熟的直播产业链。近日,记者采访到成都天府蜂巢直播产业基地即将竣工,正式进入运营阶段,作为成都科学城兴隆湖高新技术服务产业园的主打新一代成都直播基地,正积极招商中!引领大规模的平台聚合发展的树莓集团与专注城市资产运营的上市公司德商产投携手打造产业+直播赋能平台——成都天府蜂巢

MyBatis初级

文章目录一、mybatis1、概念2、JDBC缺点2.1、之前jdbc操作2.2、原始jdbc操作的分析3、mybatis的使用3.1、导入maven依赖3.2、新建表3.3、实体类3.4、编写mybatis的配置文件3.5、编写接口和映射文件3.6、编写测试类3.7、注意事项4、代理方式开发5、mybatis和spr

03MyBatis-Plus中的常用注解

常用注解@TableNameMyBatis-Plus根据BaseMapper中指定的泛型(实体类型名)确定数据库中操作的表,如果根据实体类型名找不到数据库中对应的表则会报表不存在异常//向表中插入一条数据@TestpublicvoidtestInsert(){Useruser=newUser(null,"张三",23,

华为云云耀云服务器L实例评测 | Linux系统宝塔运维部署H5游戏

文章目录前言一、云服务器相对传统服务器有什么优势1.1、可伸缩性(Scalability)1.2、灵活性(Flexibility)1.3、高可用性(HighAvailability)1.4、备份和恢复(BackupandRecovery)1.5、成本效益(Cost-Effectiveness)1.6、全球性(Globa

热文推荐