在大量内核上调试我的程序,我遇到了虚拟内存不足的非常奇怪的错误.我的调查导致了代码的和平,主机向每个从机发送小消息.然后我写了一个小程序,其中1个master只用MPI_SEND发送10个整数,所有从站用MPI_RECV接收它. MPI_SEND之前和之后的文件/ proc / self / status的比较表明,内存大小之间的差异是巨大的!最有趣的事情(崩溃了我的程序)是,这个内存在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
解决方法
这是几乎任何在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设置为1来启用XRC队列.这应该以某种方式减少使用的内存.如果程序的通信图形未完全连接(完全连接的程序是每个级别与所有其他级别对话的程序),则通过将I_MPI_OFA_DYNAMIC_QPS设置为1来启用动态队列对创建可能会降低内存使用量.