GASNet调研报告

发布时间 2023-04-28 20:48:09作者: zhuwlong

GASNet概述

在21世纪初,并行计算的编程模型主要有两种,一种是共享内存模型,另一种是分布式内存模型。共享内存模型的并行线程共享同一个内存空间,这种方式对程序员编程十分方便,但是严重影响了硬件可扩展性。分布式内存模型中的线程需要通过显式通信来访问其他节点上的内存,这种方式的硬件可扩展性强,但是编程不方便。当时的大多数超算平台已经采用分布式内存,由此产生了全局地址空间模型(global-address space model, GAS),它综合了共享内存模型和分布式内存模型的优点,把分布式内存抽象成共享内存以提供易编程性,同时对本地内存和远程内存进行区分,这样程序员就可以分别处理两种内存,同时尽可能使用访问速度更快的本地内存。

UPC语言是C语言的并行扩展,它就是一种支持GAS模型的语言,UPC中的内存分为仅能每个线程访问的私有内存和共享内存,同时每个线程对共享内存中的特定部分具有更快的访问速度(这部分内存和该线程位于同一节点)。UPC由LBL和UC Berkeley共同开发,在开发时他们发现大多数高性能的底层通信系统基于特定的硬件实现,这对编译器的可移植性带来了严重的困难。GASNet就是在这种情况下开发的,以提供高性能、可移植的底层通信系统。
image
GASNet(Global-Address Space Networking,全局地址空间网络)的结构分为两层,下层很窄,叫做core API,它提供了尽量少的API供下层实现,只要在不同的底层环境实现这些API就可以实现可移植性。上层比较宽,叫做extend API,extend API提供了供上层(GASNet 客户端,例如UPC)使用的一些更高级的操作,extend API的全部功能都由core API实现,这样在移植时就不需要额外的工作。当然在特定的情况下也可以直接用硬件实现extend API的某些功能以提供更好的性能。GASNet的这种特性实现了四个无关:与平台无关、与编译器无关、与网络无关、与编程语言无关。同时GASNet是为上层的GASNet客户端提供支持,而不是供程序员使用的编程库,所以GASNet的性能要优先于代码可读性。

image

然而,GASNet从研发至今一直比较小众,GASNet客户端主要还是Berkeley UPC,下层适配的硬件也较少,而且大多数适配是由GASNet团队实现的。从2017年开始,GASNet团队开始开发GASNet-EX,GASNet-EX被称为下一代GASNet,它是GASNet的超集,原来的GASNet被称为GASNet-1。开发GASNet-EX的目的是适配E级超级计算平台,为HPC应用提供底层通信支持,同时GASNet-EX提供了对GASNet-1的向后兼容性。当前GASNet-EX仍处于开发阶段,大量的接口仍在等待重写。

GASNet core API

GASNet core API 是基于Active Message实现的一个最小的API集合,用于实现作业控制、消息传递以及原子性控制功能,同时上层的extend API也是基于core API实现的。

Active Message

随着通信硬件的发展,通信性能越来越受制于通信协议,为了提高通信性能出现了一种用户层通信协议(User—Level Networking, ULN),这种协议允许用户程序直接读取通信接口以减少通信开销,Active Message就是ULN的一个代表。

Active Message(AM, 国内有些论文翻译为“主动消息”、“活性消息”)是由Berkeley开发的一种通信接口规范,AM 1.0版本在1992年发布,它提供了一种轻量的RPC机制。AM的特色在于在消息的头部添加了一个句柄,这个句柄指示接收方由哪个函数处理接收到的数据,发送方在发送完数据后就可以继续计算,接收方收到数据后中断当前计算、运行处理函数,然后恢复计算,这样就提高了通信效率。AM 1.0使用Request/Reply通信机制,即发送方发送数据,接收方收到数据后发送回复,发送方收到回复后这次通信结束,这种方式对编程人员来说有些复杂。1996年发布的AM2.0对AM1.0进行了大量改进,使其真正能够被实现。另外AM 2.0基于Request/Reply机制提供了单边通信Put/Get机制,这样另外一方就不需要显式参与消息传递,简化了编程。Active Message所在的“NOW”项目在1998年终止,随后AM并入了GASNet项目。

core API主要功能

首先是作业控制功能,这部分主要包括初始化作业环境、注册共享内存段、终止GASNet作业等;其次是查询功能,可以查询节点的一些信息,例如当前线程所在的节点号、总节点数以及每个节点的内存地址等。

Core API的一个重要功能是消息传递,它是AM2.0的一种实现,同时对AM2.0进行了一些改进,去掉了一些不必要的功能。Core API发送的消息有short、medium、long三种类型,其中short类型只发送几个整型参数,medium和long类型除了参数之外还可以发送额外的数据。Medium类型和long类型的区别在于medium类型的数据直接供程序使用,而long类型的数据先存放到一个缓冲区中。Core API相应地提供了三种数据类型的最大长度查询函数、request函数和reply函数。两个进程A和B的通信过程为:A运行request函数,向B发送AM消息,B收到消息后根据AM消息头部的句柄运行相应请求处理函数对数据进行运算,然后调用reply函数向A回复,A收到回复后运行相应的回复处理函数。

Core API另一个功能是原子性控制。每个处理程序可以在一个线程上运行,它可以和主线程同步或异步进行,并且不同的线程可以并行运行,但是处理程序内部不允许中断,即每个线程只允许运行一个处理程序。为了实现这一点需要原子性控制。GASNet core API实现了“非中断区”(no-interrupt sections)。非中断区由gasnet_hold_interrupts()函数和gasnet_resume_interrupts ()函数定义,它保证在当前线程上不会有处理程序异步运行。为了避免性能下降,GASNet对非中断区的持续时间进行了限制。GASNet同时实现了处理程序安全锁(Handler-Safe Lock , HSL)以支持处理程序更新和主线程以及其他处理程序共用的数据结构。

core API的实现

GASNet API的具体实现被称为“conduit”,它可以大致分为便携式(portable)conduit和本地(local)conduit。便携式conduit可以在多种设备上使用,而本地conduit特定于具体的环境实现,能提供更好的性能。

目前GASNet实现的便携式conduit有smp-conduit、udp-conduit、mpi-conduit和ucx-conduit。Smp-conduit基于共享内存实现,适用于单个共享内存的节点,udp-conduit适用于因特网或者任何基于TCP/IP的网络,mpi-conduit基于MPI实现,适用于缺乏本地conduit的节点,ucx-conduit基于Unified Communication X framework(一个统一通信框架,由AMD、arm等企业建立)实现。 GASNet实现的本地高性能conduit有aries-conduit和ibv-conduit。Aries-conduit在Cray XC Aries(Cray公司在XC系列超算机上实现的Aries互联技术)上实现,ibv-conduit基于InfiniBand上的Verbs API实现。以上conduit中ucx-conduit仍处于测试阶段,其他实现都已经比较成熟。

GASNet extend API

GASNet extend API在core API的基础上实现了更多高级功能,包括从内存到内存的数据传输、从寄存器到远程内存的数据传输、障碍同步和线程支持等。从内存到内存的传输使用put/get操作,put操作把本地内存的数据传输到远程内存,get操作把远程内存的数据传到本地。数据传输支持阻塞式传输和非阻塞式传输,阻塞式传输过程中程序会阻塞,直到传输完成。非阻塞操作的数据传输不需要阻塞程序,但是需要在put/get操作开始和结束时进行同步以确保操作正确完成。两种传输方式都既支持对齐数据传输又支持非对齐数据传输。非阻塞传输又分为显式句柄和隐式句柄,显式句柄传输会返回一个句柄用于同步操作,隐式句柄传输不会返回句柄,使用隐式句柄完成同步。

从寄存器到到远程内存的数据传输可以不经过本地内存,这样可以提高传输效率。传输同样使用put/get操作,put操作把寄存器中的值存到远程内存,get操作把远程内存中的数据读入寄存器。障碍同步功能是一种集合操作,用于同步所有线程。线程支持是可选实现,用于降低同一线程进行的多次 GASNet 调用的线程发现成本。

GASNet-EX

GASNet-EX是下一代GASNet,它开发的目标是适配E级超级计算平台,为当前和将来的HPC编程模型提供通信支持。GASNet-EX继承了GASNet-1高性能、可移植的特性,同时正在对大量的接口进行重写,以提供更好的性能和更多的新功能。GSANet-EX中的函数名由gasnet_开头变为了以gex_开头。GASNet-EX从2017年发布以来保持每季度发布一个版本的频率以尽快提供新功能。

GASNet-EX到目前为止已经发布了大量性能改进和新增功能,尽管有些实现还不是很完善。GASNet-EX提供的主要改进有:

  1. 初始化改进
    GASNet-1的初始化是端点、通信接口和内存段耦合在一起的,在GASNet-EX中,初始化的对象是一个对象模型,该模型中端点、通信接口和内存段分开显式处理,这样就能初始化更复杂的用例,而且增加了系统的模块化程度。

  2. 事件(event)和子事件(sub-event)的概念
    在GASNet-1中数据传输所返回的句柄只能表示整个操作是否完成,GASNet-EX引入了事件的概念,把整个操作分割成了很多子事件,每个子事件都有自己的完成情况,程序可以基于子事件的完成情况进行相应调整。
    子事件的一个应用是“本地完成”,把本地完成从整个操作完成中分离出来,这样只要本地的操作完成就能继续使用本地空间,而无需等待远程的操作也完成,提高了计算效率。

  3. 即时模式通信注入(Immediate-mode Communication Injection)
    GASNet支持“通信注入”,即在通信时如果遇到资源不足的情况发送stall指令,暂时将通信阻塞以等待资源,GASNet-EX引入了“即时模式”,当资源不足时返回一个信息,由客户端决定是继续等待还是做其他事情,例如调整顺序先做其他事情或者尝试和其它的进程通信。

  4. 远程原子操作
    GASNet-EX定义了远程原子操作,它包含由指定数据类型和一组原子操作构成的“原子域”,在原子域中可以原子方式对分布式内存中的指定数据类型执行原子操作。

  5. 非连续的RMA访问
    在GASNet-1上已经实现了对非连续RMA访问的扩展,称为VIS扩展(“Vector”, “Indexed” and “Strided”),但是该扩展并未集成到GASNet的正式规范中,GASNet-EX集成了该扩展,并提供了性能改进。

  6. Team(TM)概念和集合操作
    集合通信在GASNet-1中就已经实现,但是未添加到GASNet规范中,GASNet-EX正式添加了这一规范,并对API进行了一些改进。在GASNet中使用rank来标识一个进程,而GASNet-EX添加了team的概念,用(team, rank)二元组来标识一个进程。这样进程就可以添加到不同的team中,实现更复杂的集合通信,如广播操作、ReduceToOne、ReduceToAll等。

  7. 不同类型的内存支持
    GASNet-EX在2020.11.0版本中添加了“内存类型”的概念,支持非主机内存,主要添加了对显存的支持,在该版本中实现了对CUDA设备显存支持。在目前最新的2021.9.0版本中通过HIP API实现了对AMD GPU显存的支持。

除此之外GAXNet-EX还对AM进行了一系列改进以适应E级超大规模的可扩展性,并且对性能进行了改进。GAXNet-EX也对部分conduit的实现进行了改进以提高性能。

参考资料

  1. GASNet官网 https://gasnet.lbl.gov/
  2. GASNet源码仓库 https://bitbucket.org/berkeleylab/gasnet
  3. Dan B , Jeong J . GASNet: A Portable High-Performance Communication Layer for Global Address-Space Languages.2002.
  4. Bonachea D , Hargrove P H . GASNet-EX: A High-Performance, Portable Communication Library for Exascale[M]. 2019.
  5. 李家宝, 周光琦. 活性消息研究与改进[J]. 高性能计算技术, 2006, 000(004):32-36.
  6. GASNet Specification, Version 1.8.1 https://gasnet.lbl.gov/dist/docs/gasnet.html