MPI-3 中增强的单边通信

上一篇中我们介绍了 MPI-3 中引进的非阻塞通信子复制和组集合通信子创建方法,下面我们将介绍 MPI-3 中增强的单边通信方法。

MPI-2 引进了单边通信,也称远端内存访问(Remote Memory Access,RMA)。单边通信操作可以提供更高的性能(在有好的硬件支撑的情况下)和更强的功能,简化某些并行编程任务。在前面我们介绍过 MPI-2 引进的单边通信的相关概念和操作方法。MPI-3 极大地扩展了 MPI-2 的单边通信功能,澄清了一些比较模糊的概念,并且解决了限制 MPI-2 的单边通信广泛应用的一些限制。

方法接口

下面给出 MPI-3 中扩展的单边通信相关方法(MPI.Win 类方法)。

窗口创建

Create_dynamic(type cls, Info info=INFO_NULL, Intracomm comm=COMM_SELF)

创建并返回用于单边通信的窗口对象,返回的窗口对象没有为其分配的内存。在组内通信子 comm 所指定的通信子范围内所有进程上执行集合操作。info 对象用于为 MPI 环境提供优化所需的辅助信息,可用的 key 有:

  • no_locks:如果为 True,会假定所创建的窗口不会被加锁(即调用 MPI.Win.Lock 或者 MPI.Win.Lock_all)。如果只使用主动同步,则可以设定此 key 为 True,此时 MPI 实现可对单边操作做一些优化。
  • accumulate_ordering:默认情况下对同一个窗口的多个 Accumulate 操作会按照严格的调用顺序执行。如果将此 key 设置成 none,则 MPI 实现不会保证对同一个窗口的多个 Accumulate 操作的执行顺序。该 key 也可以设置成一系列由逗号分隔的 rar (read-after-read), war (write-after-read), raw (read-after-write) 和 waw (write-after-write) 以指明相应的执行顺序。放松对执行顺序的限制可能会提高执行效率。
  • accumulate_ops:如果设置成 same_op,MPI 实现会假定对窗口的同一目的地址的并发 Accumulate 调用都会使用同样的算符。如果设置成 same_op_no_op,MPI 实现会假定对窗口的同一目的地址的并发 Accumulate 调用都会使用同样的算符或者 MPI.NO_OP。该 key 的默认值为 same_op_no_op。
Allocate(type cls, Aint size, int disp_unit=1, Info info=INFO_NULL, Intracomm comm=COMM_SELF)

分配指定大小的内存并创建和返回用于单边通信的窗口对象。在组内通信子 comm 所指定的通信子范围内所有进程上执行集合操作。每个进程所返回的窗口对象会包含一块分配好的 size 大小的内存。每个进程的 size 可以不同,甚至可以为 0。disp_unit 指定在远端内存访问操作中的地址单位,即 origin 所指定的位置在 target 一侧要以 target 进程所指定的 diap_unit 为单位计算。通常如果采用相同类型创建窗口,则统一将 disp_unit 设置成 1 即可。如果有的进程需要以组合数据类型(type)给出缓冲区,则可能需要指定 disp_unit 为 sizeof(type)。info 对象用于为 MPI 环境提供优化所需的辅助信息。

Allocate_shared(type cls, Aint size, int disp_unit=1, Info info=INFO_NULL, Intracomm comm=COMM_SELF)

创建并返回一个拥有共享内存的窗口对象。MPI-3 共享内存相关操作将在下一篇中介绍。

Attach(self, memory)

给当前窗口对象对象(由 Create_dynamic 所创建的窗口对象)加载一块内存 memory

Detach(self, memory)

卸载当前窗口对象(由 Create_dynamic 所创建的窗口对象)的内存 memory

单边操作

Rput(self, origin, int target_rank, target=None)

对应 MPI.Win.Put 操作,参数也同 MPI.Win.Put,不同的是该方法返回一个 MPI.Request 对象,该对象的完成(可通过 Wait,Test 等)意味着发送的进程可以更改其 origin 数据缓冲区,但并不表示目标进程的窗口已经完成了数据的接收(需要通过 MPI.Win.Flush,MPI.Win.Flush_all,MPI.Win.Unlock,MPI.Win.Unlock_all 等来完成)。

Rget(self, origin, int target_rank, target=None)

对应 MPI.Win.Get 操作,参数也同 MPI.Win.Get,不同的是该方法返回一个 MPI.Request 对象,该对象的完成(可通过 Wait,Test 等)意味着 origin 缓冲区已经从远端拿到数据。

Raccumulate(self, origin, int target_rank, target=None, Op op=SUM)

对应 MPI.Win.Accumulate 操作,参数也同 MPI.Win.Accumulate,不同的是该方法返回一个 MPI.Request 对象,该对象的完成(可通过 Wait,Test 等)意味着发送的进程可以更改其 origin 数据缓冲区,但并不表示目标进程的窗口已经完成了数据的更新(需要通过 MPI.Win.Flush,MPI.Win.Flush_all,MPI.Win.Unlock,MPI.Win.Unlock_all 等来完成)。

Get_accumulate(self, origin, result, int target_rank, target=None, Op op=SUM)

该操作将 origin 中的数据用 Reduce 中所定义的操作 op 更新 target_rank 的窗口缓冲区中由 target 所指定位置处的数据,并通过 result 返回target_rank 的窗口缓冲区中未被 accumulate 更新前的数据。除 result 外,其它参数同 MPI.Accumulate 方法。op 可以使用 Reduce 内置定义的操作,MPI.REPLACE 和 MPI.NO_OP,但是不能使用用户自定义的算符。操作的数据只能是预定义的数据类型或由同一种预定义数据类型创建的用户自定义数据类型。

Rget_accumulate(self, origin, result, int target_rank, target=None, Op op=SUM)

对应 MPI.Win.Get_accumulate 操作,参数也同 MPI.Win.Get_accumulate,不同的是该方法返回一个 MPI.Request 对象,该对象的完成(可通过 Wait,Test 等)意味着发送的进程可以更改其 origin 数据缓冲区,并且 result 已经拿到数据,但并不表示目标进程的窗口已经完成了数据的更新(需要通过 MPI.Win.Flush,MPI.Win.Flush_all,MPI.Win.Unlock,MPI.Win.Unlock_all 等来完成)。

Fetch_and_op(self, origin, result, int target_rank, Aint target_disp=0, Op op=SUM)

是 Get_accumulate 的简化版本,只能操作单个数据项(由操作的数据类型定义),除 target_disp 外其它参数与 Get_accumulate 的对应参数同。target_disp 指定要操作的远程窗口的起始偏移位置。

Compare_and_swap(self, origin, compare, result, int target_rank, Aint target_disp=0)

compare 中的数据与 target_rank 窗口缓冲区中偏移 target_disp 处的单个数据项进行比较,如果相同则用 origin 中的数据替换target_rank 窗口缓冲区中偏移 target_disp 处的数据,并由 result 返回未被替换前的数据。操作的数据类型只能是以下几种:C 整型、Fortran 整型、布尔型、Byte 型等。

同步操作

Lock_all(self, int assertion=0)

对该窗口对象中的所有进程启动一个访问时间段,加锁的类型为 MPI.LOCK_SHARED(共享锁)。在此访问时间段内调用此方法的进程可以通过单边通信操作访问该窗口对象的所有进程的窗口缓冲区。必须用配对的 Unlock_all 来解锁。该方法不是一个集合操作,ALL 是指该窗口包含的所有进程。assertion 除了默认的 0 之外可以设置为 MPI.MODE_NOCHECK,表示在尝试创建锁时,可以确信没有其它进程已经取得了相同窗口对象的锁,或者正在尝试获取窗口对象的锁。

Unlock_all(self)

与 Lock_all 配对,标记一个访问时间段的结束。该方法返回后在该访问时间段内的所有单边通信操作的源端和目的端都会完成。

Flush(self, int rank)

该方法完成调用进程对 rank 进程的所有单边访问操作,源端和目的端都会完成。只能用在被动同步的访问时间段内。

Flush_all(self)

该方法完成调用进程的所有单边访问操作,源端和目的端都会完成。只能用在被动同步的访问时间段内。

Flush_local(self, int rank)

该方法完成调用进程对 rank 进程的所有单边访问操作的本地源端缓冲区。该方法返回后当前进程就可以重新使用提供给 Put,Get,Accumulate 方法的 origin 缓冲区。只能用在被动同步的访问时间段内。

Flush_local_all(self)

该方法完成调用进程的所有单边访问操作的本地源端缓冲区。该方法返回后当前进程就可以重新使用提供给 Put,Get,Accumulate 方法的 origin 缓冲区。只能用在被动同步的访问时间段内。

Sync(self)

同步当前窗口的私有和公共内存区。它并不会完成一些尚未完成的单边通信操作。

例程

下面给出上面介绍的部分方法的使用例程。

# mpi3_rma.py

"""
Demonstrates the usage of MPI-3 enhanced RMA.

Run this with 4 processes like:
$ mpiexec -n 4 python mpi3_rma.py
"""

import numpy as np
from mpi4py import MPI


comm = MPI.COMM_WORLD
rank = comm.Get_rank()

# Create
if rank == 0:
    win = MPI.Win.Create(None, comm=comm)

    # Lock_all
    win.Lock_all()
    for rk in [1, 2, 3]:
        a = np.array([rk, rk], dtype='i')
        # Put
        win.Put(a, target_rank=rk)
        print 'rank %d put %s to rank %d' % (rank, a, rk)
    # Unlock_all
    win.Unlock_all()

    # Lock for rank 1
    win.Lock(rank=1)
    b = np.array([10, 10], dtype='i')
    c = np.array([-1, -1], dtype='i')
    # Get_accumulate
    win.Get_accumulate(b, c, target_rank=1, op=MPI.SUM)
    # Unlock for rank 1
    win.Unlock(rank=1)
    print 'rank %d Get_accumulate %s to rank 1, and get result %s' % (rank, b, c)

    comm.Barrier()
else:
    mem = np.array([-1, -1], dtype='i')
    win = MPI.Win.Create(mem, comm=comm)
    comm.Barrier()

    print 'rank %d get %s' % (rank, mem)


# Allocate
if rank == 0:
    win = MPI.Win.Allocate(0, disp_unit=4, comm=comm)
    # Lock_all
    win.Lock_all()
    reqs = []
    for rk in [1, 2, 3]:
        a = np.array([rk, rk], dtype='i')
        # Rput
        req = win.Rput(a, target_rank=rk)
        reqs.append(req)
        print 'rank %d put %s to rank %d' % (rank, a, rk)
    # compute all Rput
    MPI.Request.Waitall(reqs)
    # Unlock_all
    win.Unlock_all()
    comm.Barrier()
else:
    win = MPI.Win.Allocate(8, disp_unit=4, comm=comm)
    comm.Barrier()
    # convert the memory of win to numpy array
    buf = np.array(buffer(win.tomemory()), dtype='B', copy=False)
    mem = np.ndarray(buffer=buf, dtype='i', shape=(2,))

    print 'rank %d get %s' % (rank, mem)


# Create_dynamic
win = MPI.Win.Create_dynamic(comm=comm)
mem = MPI.Alloc_mem(8)
# Attach and Detach
win.Attach(mem)
win.Detach(mem)
MPI.Free_mem(mem)

运行结果如下:

$ mpiexec -n 4 python mpi3_rma.py 
rank 0 put [1 1] to rank 1
rank 0 put [2 2] to rank 2
rank 0 put [3 3] to rank 3
rank 0 Get_accumulate [10 10] to rank 1, and get result [1 1]
rank 1 get [11 11]
rank 2 get [2 2]
rank 3 get [3 3]
rank 0 put [1 1] to rank 1
rank 0 put [2 2] to rank 2
rank 0 put [3 3] to rank 3
rank 3 get [3 3]
rank 1 get [1 1]
rank 2 get [2 2]

以上介绍了 MPI-3 中增强的单边通信方法,在下一篇中我们将介绍 MPI-3 中共享内存操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容

  • 在上一篇中我们介绍了 mpi4py 中的近邻集合通信方法,下面我们将介绍 mpi4py 中的非阻塞通信子复制和组集...
    自可乐阅读 1,311评论 0 0
  • 前言 计算机编程语言很多,但是适合高性能数值计算的语言却并不多,在高性能计算的项目中通常会使用到的语言有 Fort...
    自可乐阅读 19,722评论 3 22
  • 在上一篇中我们概要地介绍了最新的 MPI-3 标准中引进的新特性,mpi4py 3.0.0 支持 MPI-3 的很...
    自可乐阅读 2,734评论 0 0
  • 在上一篇中我们介绍了 SLURM 资源管理系统,下面将介绍 MPI-3 的新特性。 在前面我们介绍了 MPI 的基...
    自可乐阅读 3,796评论 1 0
  • 1.设置属性类型 通过修改propsType来实现,恩,比较奇怪的写法,感受下 2.构造属性 通过construc...
    踏云小子阅读 1,054评论 0 1