GPU卡的底层通信原理

1.引言

为什么要并行

近几年,依赖大规模标注数据和大量的可学习参数,深度神经网络才能异军突起,占得机器学习半壁江山。然而,也是因为这两点使得深度学习的训练变得极其困难,尤其是对语音和图像这样的大型非结构化数据来说,训练更加困难。即使通过GPU卡加速可以缓解这个问题,但是单卡上能够放置的数据量还是有限的,所以给超大数据集(如图像数据集ImageNet)带来的加速仍然杯水车薪。基于以上单卡硬件能力的局限性,进一步加速训练就需要诉诸于分布式训练,即使用单机多卡或多机多卡的进行模型训练,从而起到加速训练的效果。

2.基础知识

2.1 为什么要了解GPU底层通信知识

目前主流的深度学习框架都已经封装了使用上很友好的基于多GPU的分布式数据并行训练功能(Distributed DataParrallel, DDP),但是只有充分了解了DDP的底层知识和工作原理,才能更好地理解并使用DDP,并且排查可能出现的并行加速性能问题。本文便是尝试进一步深挖多GPU卡的底层工作原理,网上关于DDP的实现和原理已经有很多比较全面的文章(例如Pytorch的官方文档),所以本文不会包含这些内容。

2.2 多GPU与CPU的物理连接及拓扑

不管单机多卡还是多机多卡,多个卡之间都会进行数据交换(推理激活值或者梯度)。为了能够更好地了解多GPU卡是如何通信或进行数据交换,我们首先得从多GPU卡在物理主板上的连接拓扑开始探究。后面讨论的内容基础都是基于Intel X86架构,其他架构(如IBM PowerPC)不在讨论范围内。在Intel X86架构下讨论多GPU卡的物理连接,则不得不讨论PCI和PCIe相关内容。

2.2.1 PCI

我们知道,现代计算机是以存储(寄存器和内存)和CPU为中心的(主要是存储),其他的如键盘、显示器和磁盘等设备相对内存和CPU来说都是外围设备(又称I/O设备,简称外设),因为他们本身没有汇总多方数据并进行逻辑运算的能力。例如,显示器显示的字符或图像只是CPU计算的结果,键盘也只是告知CPU人类输入了什么字符,收到字符后的其他操作就是CPU的任务了。有些外设是用来与人类进行交互的,例如显示器和键盘,它们一个从CPU获取数据,一个向CPU发送数据;有些外设是提供数据持久化的,如磁盘,因为寄存器和内存都是非永久性存储,断电后所有数据就会丢失,使用磁盘我们可以将CPU执行的结果进行持久化保存;有些外设是进行多个主机CPU之间数据交换的,例如网卡;而有些外设执行的任务更加特殊,比如GPU,它的作用主要是帮助CPU分担大量的数值计算任务,一开始GPU的作用主要是执行图形相关运算的,从而让CPU腾出更多的时间执行逻辑计算。从上面的描述我们可以看出,大量的外设都要与CPU或内存进行数据交换,外设有很多,CPU只有一个或几个,这时CPU就成为了稀缺资源,因为同一时间单一CPU不可能同时与磁盘和显示器进行通信。这时就需要有一套提前声明的规定,也就是协议,来规范所有外设与CPU的通信行为,在Intel X86架构中,这便是早期的PCI协议。

PCI(Peripheral Component Interconnect,外围设备互连)总线和设备树是X86硬件体系架构中很重要的组成部分,几乎所有的外围硬件都以这样或那样的形式连接到PCI设备树上。下面是桌面系统主机常见的PCI总线树。

图中有两个总线,分别为“PCI Local Bus #0”和“PCI Local Bus #1”。从图中我们可以了解之所以将PCI总线称为总线树,是因为PCI支持总线扩展,即当0号总线不够用时(接入更多的设备,但总线插槽数有限),可以通过“PCI-to-PCI Bridge”进行扩展,PCI-to-PCI Bridge可以连接其他总线,如果以与CPU直接连接的总线作为树的根节点的话,其他的外设加上通过扩展增加的外设就构成了一个设备树。

另外,从图中也可以看出PCI总线结构是一种共享总线结构,即挂载在同一总线上的设备之间是共享总线带宽的。随着PCI设备读写速度不断提高(如显卡、网卡等设备),这种架构就变得不适用了,经过几代的更新,最终从PCI架构演变出目前主流的PCIe架构。

2.2.2 PCIe

PCIe(Peripheral Component Interconnect Express),即高速的PCI,其在PCI的基础上做了很多扩展,其中一个就是“PCIe是点对点结构,而PCI是总线结构”,一个典型的PCIe系统结构图如下:

点对点意味着每一个PCIe设备都拥有自己独立的数据连接,设备之间数据传输并发互不影响,而对于PCI共享总线方式,PCI总线上只能有一个设备进行通信,一旦PCI总线上挂接的设备增多,每个设备的实际传输速率就会下降,性能得不到保证。PCIe以点对点的方式处理通信,每个设备在要求传输数据的时候各自建立自己的传输通道,对于其他设备这个通道是封闭的,这样的操作保证了通道的专有性,避免其他设备的干扰。例如,图中最右下角的两个外设(两个PCI Express Endpoint)想要通信的话,只需要通过直连的Switch设备进行数据交换(类似于网络交换机),而不必通过“外设1-->CPU-->外设2-->CPU-->外设1”这样的链路进行数据交互,这样就不会左上角的外设与其他设备或者CPU进行数据交互的带宽。当然,这两个外设的数据交互还是会影响挂载在同一Switch设备上的其他外的带宽,但这样也大大降低了PCI中外设数据必须通过CPU才能进行交互的问题。

图中的Root Complex是各种资源的集合,如中断控制器、电源管理控制器、内存控制器、错误检测和报告逻辑等。Root Complex也包含一个内部总线(Host Bridge),它表示整个PCIe树结构中的0号总线。它代表处理器发起外设事务请求,从它的端口发送数据包或在它的端口接收数据包,然后传输到内存。我们在下文中还会遇到Root Complex和Host Bridge。

2.2.3 NUMA

服务器的情况要复杂一点,这需要了解NUMA的概念:就如之前说的,在若干年前,对于x86架构的计算机,那时的内存控制器还没有整合进CPU,所有内存的访问都需要通过北桥芯片来完成。此时的内存访问如下图所示,被称为UMA(uniform memory access, 一致性内存访问 )。这样的访问对于软件层面来说非常容易实现:总线模型保证了所有的内存访问是一致的,不必考虑由不同内存地址之前的差异。

之后的x86平台经历了一场从“拼频率”到“拼核心数”的转变(核心就是CPU中最小的逻辑运算单元,核心越多,同时并发执行任务的任务数量就越多),越来越多的核心被尽可能地塞进了同一块芯片上,各个核心对于内存带宽的争抢访问成为了瓶颈,因此X86推出了NUMA(Non-uniform memory access, 非一致性内存访问)架构(还有其他的原因),示意图如下:

从图中我们可以得出NUMA架构的两个特点:
1.CPU芯片被划分成不同的组,称为node,每个node有自己独立的内存访问地址,每个node也就有自己的内存单元;
2.如果想要跨node访问内存(如node0想要访问下面的内存),则需要通过跨node的CPU通信进行数据交互(node之间通过QPI连接)。

下图是我手头使用的一台服务器的node和CPU数量,该信息是命令lscpu的显示结果, 从图中可以看出,这条服务器将2个CPU芯片(每个芯片有20个核心)划分成两个组(node), 其中0 ~ 9和20 ~ 29号核心属于属于node0,10 ~ 19和30~39核心属于node1:

既然内存划分给不同的CPU组(即node),那么类似地,将PCI设备划分给不同的node,也会提高外设与特定CPU的数据交换效率。同样,如果想要跨node访问PCI外设,也需要经过QPI连接进行跨node的CPU通信进行数据交互。在NUMA架构下具有两个node(即两个CPU芯片组)的PCIe物理结构如下图,图中每个node只有一个CPU芯片,所以用CPU代替了node:

上图中差不多就是简易的现代服务器的物理连接结构图,从图中我们可以看出,如果一个服务器上挂载了多个GPU卡,可能由于每个卡挂载的物理位置不同,GPU之间的通信链路方式就会有多种,使用命令nvidia-smi topo --matrix可以直接获得服务器上每两个卡之间的物理通信方式:

可以看出,英伟达给出了6中GPU卡的物理通信方式,下面我们可以结果上面的PCIe物理结构图来了解这些通信方式:
SYS: 通过QPI(PCIe + QPI总线)跨NUMA node间GPU通信,相当于上上图中的GPU1到GPU5;
NODE: 单个NUMA node内经过Host Bridge PCIe总线通信(一个NUMA node上有多个CPU芯片),没遇到过这种情况,就不举例子了;
PHB: 经过Host Bridge(Root complex中)的PCIe总线通信,同一Root complex下多个PCIe总线,相当于上上图中的GPU1到GPU3;
PXB: 跨越多个PCIe Bridge (switch),但没有经过Host Bridge PCIe总线,相当于上上图中的GPU3到GPU4;
PIX: 经过一个PCIe Bridge (switch)通信,即挂载在同一个PCIe Bridge上的GPU卡之间通信,相当于上上图中的GPU1到GPU2;
NV#: 使用NVLink通信(后面会介绍);
描述中所指的Host Bridge就是Host主桥,是连接处理器和PCI总线的一个设备器件,用来隔离处理器的存储器域与PCI总线域的特殊桥片,管理PCI总线域,集成在Root Complex中,此处可以认为就是图中的Root Complex。

从上面的例子可以直观地看出,两个GPU卡的物理距离越近(如GPU1到GPU2),则通信效率越高,距离越远效率越低,此处的效率一般体现在通信时延上。

2.3 GPU通信技术

GPU强大的并行计算能力,大大提升了运算性能。随着运算数据量的不断攀升,GPU间需要交换大量的数据,GPU通信性能成为并行计算非常重要的性能指标。前面介绍的NUMA架构和PCIe协议只是物理层面的协议(类似于网络协议中的物理层和数据链路层),如何在其上进行高效的GPU通信是接下来的内容(类似于网络协议中的IP层和传输层)。

GPU通信的发展简史如下:
GPUDirect Shared Memory (2012) : Nvidia在PCIe上实现了单机上的GPUDirect Shared Memory 技术;
GPUDirect P2P (2014): Nvidia在PCIe上实现了单机上的GPUDirect P2P技术;
NVLink(2014) :解决了单机多卡通信时PCIe瓶颈问题;
GPUDirect RDMA(2014):提升多机多卡通信性能;

2.3.1 GPUDirect Shared Memory

Nvidia在PCIe上实现了单机上的GPUDirect Shared Memory 技术,使得GPU与第三方PCIe设备通过共享的固定的(pinned)CPU内存实现共享内存访问从而加速通信,原理如下图所示:

此处的“固定的CPU内存”指的就是我们在使用Pytorch的DataLoader时指定的pin_memory参数,由于设置pin_memory=True后会导致部分CPU内存无法被其他进程使用并且无法参与Swap换出到磁盘,如果在主机内存不足时设置该参数,则会造成服务器运行效率降低。

2.3.2 GPUDirect P2P

后来GPUDirect又增加了相同PCI Express root complex下的GPU之间的内存数据直接访问或交换的能力,即Peer to Peer(P2P) Direct Access和Direct Transfers,进一步降低了GPU数据交换的成本,原理如下图所示:

2.3.3 NVLink

由于PCIe带宽瓶颈问题,Nvidia直接放弃使用PCIe,提出了NVLink通信协议,能在多GPU之间和GPU与CPU之间实现更高的通信带宽,但是放弃PCIe也就相当于放弃Intel X86,所以目前在主流的X86服务器上是看不到NVLink的。

2.3.4 GPUDirect RDMA

对于大规模深度学习训练任务,单机已经无法满足计算要求,多机多卡的分布式训练成了必要的需求,多机间的通信成为了分布式训练性能的重要指标,因此GPUDirect增加了对RDMA( Remote Direct Memory Access )的支持,使得GPU可以不经过CPU直接访问其他主机上GPU卡的内存数据。

目前我们使用的X86单个服务器用不到NVLink和RDMA,主要GPU通信受益于P2P技术,下面是我手头使用的服务器在使用P2P后的GPU卡通信时延对比(该数据使用p2pBandwidthLatencyTest工具得到)。

下图是0~7卡P2P连接情况,1代表支持P2P连接,0代表不支持:

从图中红框可以看到,使用P2P技术后GPU间通信实验降低了2~3倍。

2.4 多卡信息收集(collective)通信技术NCCL

之前介绍的都是GPU的物理连接和通信协议,开发者想要使用这些功能进行多卡通信(如深度学习框架中支持多卡方式训练模型),则需要在其之上封装一个友好的库(类似于操作系统提供的socket通信编程接口)。这便是NCCL(Nvidia Collective multi-GPU Communication Library)诞生的目的:它是一个实现多GPU的数据汇集(collective)通信库,支持的数据通信原语有reduce,all-reduce,broadcast ,gather,all-gather等;使用ring-based的collective通信方式,可以显著降低通信时间;同时NCCL做了很多优化,可以在PCIe、NVLink、InfiniBand上实现较高的通信速度。

下面简单介绍几个常用NCCL通信原语的原理:

  • NCCL通信原语——reduce,从多个sender那里接收数据,最终combine到一个节点上
  • NCCL通信原语——all-reduce,从多个sender那里接收数据,最终combine到每一个节点上
  • NCCL通信原语——broadcast,从单个sender数据发送到其他节点上
  • NCCL通信原语——gather,将多个sender上的数据收集到单个节点上

另外,需要额外介绍下NCCL的ring-base collective通信方式,它将所有的通信节点(GPU卡)通过首尾连接形成一个单向环,数据在环上依次传输,使用ring-base collective具有以下好处:

  1. 去掉数据(参数)服务器节点的概念,所有在环中的节点功能相同,通过分摊通信负载从而降低单个节点的通信压力;
  2. 可以实现通信时间不随节点数的增加而增加,只和数据总量以及带宽有关;

下面是传统的单server多worker和多server多worker通信模式,不管哪种通信模式,它们的最大缺点是随着通信节点的增加,将极大增加网络通信压力,尤其是server端的通信压力,因为所有节点的数据都要先汇聚到server上,然后在分发到每个节点上。

下面是以传统方式broadcast通信原语实现的示意图:

从上面的图中可以看出传统broadcast操作的通信时间适合GPU卡的数量相关的(图中公式(k-1)N/B),下面用ring-base collective通信方式实现broadcast通信原语的示意图,可以看出当数据分块的数量S远大于GPU卡数k时,通信耗时接近N/B,而该值只由通信数据的总量N和通信带宽B有关,与GPU卡数无关。

all-reduce操作也有类似的操作:

下图是NCCL ring-base collective通信方式在单机8卡之间构造的通信环路(该图是理想情况下:每四张卡挂载同一Switch上):

目前主流的深度学习框架,使用NVIDIA GPU计算时,DDP的多卡数据同步基本上使用NCCL是效率最高的,如下是Pytorch使用DDP时指定NCCL作为通信方式的官方示例代码

import torch
import torch.multiprocessing as mp

def example(rank, world_size):
    # create default process group
    torch.distributed.init_process_group(backend="nccl", 
                                        init_method="tcp://127.0.0.1:8790", 
                                        world_size=world_size, rank=rank)
    # create local model
    model = torch.nn.Linear(10, 10).to(rank)
    # construct DDP model
    ddp_model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[rank])
    # define loss function and optimizer
    loss_fn = torch.nn.MSELoss()
    optimizer =  torch.optim.SGD(ddp_model.parameters(), lr=0.001)

    # forward pass
    outputs = ddp_model(torch.randn(20, 10).to(rank))
    labels = torch.randn(20, 10).to(rank)
    # backward pass
    loss_fn(outputs, labels).backward()
    # update parameters
    optimizer.step()

def main():
    world_size = 2
    mp.spawn(example, args=(world_size,), nprocs=world_size, join=True)

if __name__=="__main__":
    main()

以上就是本文的所有内容,如有错漏之处欢迎指正。

3.参考资料

  1. 深挖NUMA
  2. 浅析GPU通信技术(上)-GPUDirect P2P
  3. https://developer.aliyun.com/article/599183
  4. https://developer.aliyun.com/article/603617
  5. 如何理解Nvidia英伟达的Multi-GPU多卡通信框架NCCL?
  6. 深入PCI与PCIe之一:硬件篇
  7. THE PCI EXPRESS BUS
  8. PCI Overview: PCI vs PCI Express
  9. Horovod: fast and easy distributed deep learning in TensorFlow
  10. NCCL: ACCELERATED MULTI-GPU
    COLLECTIVE COMMUNICATIONS
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容

  • 1. CPU 并行 1.1 概述 之所以先从 CPU 聊起而不是直接切入正题讲 GPU, 是因为并行思想在CPU和...
    Teci阅读 4,750评论 1 5
  • 通信总线 取地址,虽然是地址,但是cpu在取的时候只是数儿而已,所以是用数据总线usb主要是通信功能,数据功能,通...
    无所用心人阅读 2,198评论 1 9
  • 学号:16020120050 姓名:吴言凡 转自:https://www.zhihu.com/question/6...
    离原_ca70阅读 3,723评论 1 2
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,454评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,534评论 0 11