MPI_SEND占据了虚拟内存的很大一部分

vov*_*ovo 7 linux mpi infiniband intel-mpi

在大量内核上调试我的程序,我遇到了非常奇怪的错误insufficient virtual memory.我的调查导致代码的和平,主机向每个从机发送小消息.然后我写了一个小程序,其中1个master只发送10个整数,MPI_SEND所有从属接收它MPI_RECV./proc/self/status前后文件的比较MPI_SEND表明,内存大小之间的差异是巨大的!最有趣的事情(崩溃我的程序)是,这个内存不会释放后MPI_Send仍然占用大量空间.

有任何想法吗?

 System memory usage before MPI_Send, rank: 0
Name:   test_send_size                                                                                
State:  R (running)                                                                                  
Pid:    7825                                                                                           
Groups: 2840                                                                                        
VmPeak:   251400 kB                                                                                 
VmSize:   186628 kB                                                                                 
VmLck:        72 kB                                                                                  
VmHWM:      4068 kB                                                                                  
VmRSS:      4068 kB                                                                                  
VmData:    71076 kB                                                                                 
VmStk:        92 kB                                                                                  
VmExe:       604 kB                                                                                  
VmLib:      6588 kB                                                                                  
VmPTE:       148 kB                                                                                  
VmSwap:        0 kB                                                                                 
Threads:    3                                                                                          

 System memory usage after MPI_Send, rank 0
Name:   test_send_size                                                                                
State:  R (running)                                                                                  
Pid:    7825                                                                                           
Groups: 2840                                                                                        
VmPeak:   456880 kB                                                                                 
VmSize:   456872 kB                                                                                 
VmLck:    257884 kB                                                                                  
VmHWM:    274612 kB                                                                                  
VmRSS:    274612 kB                                                                                  
VmData:   341320 kB                                                                                 
VmStk:        92 kB                                                                                  
VmExe:       604 kB                                                                                  
VmLib:      6588 kB                                                                                  
VmPTE:       676 kB                                                                                  
VmSwap:        0 kB                                                                                 
Threads:    3        
Run Code Online (Sandbox Code Playgroud)

Hri*_*iev 10

这是几乎任何在InfiniBand上运行的MPI实现的预期行为.IB RDMA机制要求应该注册数据缓冲区,即它们首先被锁定在物理内存中的固定位置,然后驱动程序告诉InfiniBand HCA如何将虚拟地址映射到物理内存.这是非常复杂的,因此注册内存以供IB HCA使用的过程非常缓慢,这就是为什么大多数MPI实现永远不会注册曾经注册的内存,希望以后将相同的内存再次用作源或数据目标.如果已注册的内存是堆内存,则它永远不会返回到操作系统,这就是为什么您的数据段的大小只会增加.

尽可能重用发送和接收缓冲区.请记住,通过InfiniBand进行通信会导致高内存开销.大多数人并没有真正考虑这个问题,而且通常记录很少,但InfiniBand使用了许多特殊的数据结构(队列),这些结构在进程的内存中分配,并且这些队列随着进程的数量而显着增长.在一些完全连接的情况下,队列内存的数量可能很大,以至于实际上没有为应用程序留下任何内存.

有一些参数可以控制英特尔MPI使用的IB队列.在您的情况下,最重要的是I_MPI_DAPL_BUFFER_NUM控制预分配和预注册内存的数量.它的默认值是16,所以你可能想减少它.但请注意可能的性能影响.您还可以尝试通过设置I_MPI_DAPL_BUFFER_ENLARGEMENT为使用动态预分配缓冲区大小1.启用此选项后,Intel MPI最初会注册小缓冲区,如果需要,稍后会增加它们.另请注意,IMPI会延迟打开连接,这就是为什么只有在调用之后才会看到使用内存大幅增加的原因MPI_Send.

如果不使用DAPL传输,例如使用ofa传输,那么您无能为力.您可以通过设置I_MPI_OFA_USE_XRC为启用XRC队列1.这应该以某种方式减少使用的内存.此外,通过设置启用动态队列对创建I_MPI_OFA_DYNAMIC_QPS1可能会降低内存的使用,如果你的程序的通信图是未完全连接(完全连接的程序是一个在每个级别会谈,所有其他等级).


Gre*_*sev 5

Hristo的答案大多是正确的,但由于你使用的是小消息,所以有一点不同.消息最终出现在急切的路径上:它们首先被复制到已经注册的缓冲区,然后该缓冲区用于传输,接收方将消息从其末端的急切缓冲区中复制出来.在代码中重用缓冲区只会有助于处理大型邮件.

这样做是为了避免注册用户提供的缓冲区的速度慢.对于大型消息,副本比注册时间更长,因此使用集合协议.

这些急切的缓冲区有点浪费.例如,默认情况下,它们在具有OF动词的英特尔MPI上为16kB.除非使用消息聚合,否则每个10-int大小的消息正在占用4个4kB页面.但无论如何,在与多个接收器通信时,聚合将无济于事.

那么该怎么办?减少热切缓冲区的大小.这是通过设置eager/rendezvous阈值(I_MPI_RDMA_EAGER_THRESHOLD环境变量)来控制的.尝试2048甚至更小.请注意,这可能会导致延迟增加.或者更改I_MPI_DAPL_BUFFER_NUM变量以控制这些缓冲区的数量,或者尝试Hristo建议的动态调整大小功能.假设您的IMPI正在使用DAPL(默认值).如果直接使用OF动词,则DAPL变量将不起作用.


编辑:所以让这个运行的最终解决方案是设置I_MPI_DAPL_UD=enable.我可以推测魔法的起源,但我无法访问英特尔的代码来实际证实这一点.

IB可以具有不同的传输模式,其中两个是RC(可靠连接)和UD(不可靠数据报).RC需要主机之间的显式连接(如TCP),并且每个连接花费一些内存.更重要的是,每个连接都有与之相关的急切缓冲区,这确实加起来了.这是英特尔默认设置的结果.

可以进行优化:在连接之间共享急切缓冲区(这称为SRQ - 共享接收队列).还有一个名为XRC(扩展RC)的Mellanox扩展,它进一步实现了队列共享:在同一节点上的进程之间.默认情况下,Intel的MPI通过DAPL访问IB设备,而不是直接通过OF动词访问IB设备.我的猜测是这排除了这些优化(我没有DAPL的经验).通过设置I_MPI_FABRICS=shm:ofaI_MPI_OFA_USE_XRC=1(使英特尔MPI使用OFA接口而不是DAPL)可以启用XRC支持.

当您切换到UD传输时,您可以在缓冲区共享的基础上进一步优化:不再需要跟踪连接.缓冲区共享在此模型中很自然:由于没有连接,所有内部缓冲区都在共享池中,就像SRQ一样.因此可以节省更多内存,但需要付出代价:数据报交付可能会失败,并且由软件而不是IB硬件来处理重新传输.当然,这对使用MPI的应用程序代码都是透明的.