You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ScaLAPACK子程序PDGEMR2D出现内存不足错误

问题:ScaLAPACK pdgemr2d 内存不足问题处理

问题背景

使用ScaLAPACK的PDSYEV子程序计算大型哈密顿矩阵(N>15000)的全谱,计算过程表现正常。但将所有特征态合并到单个进程的全局矩阵时,N≤20000时pdgemr2d可以正常工作,N更大时触发内存不足错误:

cannot allocate memory, aborted xxmr2d: out of memory

集群配置:128GB内存、32CPU/64线程。

代码结构

.... 
   call MPI_INIT(info)
   call MPI_COMM_RANK(MPI_COMM_WORLD, myrank, info)
   call MPI_COMM_RANK(MPI_COMM_WORLD, nprocs, info)
   call MPI_COMM_SIZE(MPI_COMM_WORLD, nsize, info)
   nprow = 4
   npcol = 4
   block = 6
   call  blacs_get(-1,0,ictxt)
   call  blacs_gridinit(ictxt,"R",nprow, npcol)
   call  blacs_gridinfo(ictxt, nprow, npcol, myrow, mycol)
  ! print*, "myrank", myrank, myrow,mycol
   np = numroc(nst,block,myrow,0,nprow)
   nq = numroc(nst,block, mycol, 0,npcol)
   lld = max(1,np)
   call descinit(descAloc,nst,nst,block,block, 0,0, ictxt,np,info)
  ! print*, "INFO descinit A", info
  ! print*, "descAloc", descAloc
   call DESCINIT(descZ, nst, nst, block, block, 0, 0, ictxt,np, info)
   call DESCINIT(descZglobal, nst, nst, nst, nst, 0,0,ictxt,nst,info)
   call DESCINIT(descdumm, nst,nst,block,block,0,0,ictxt,np,info)
   !print*, "info descinit Z", info
   pi=acos(-1.d0) ! value of pi
   fi = 0.0/N_site
   phase =  dcmplx(cos(fi),sin(fi))
  
   !if  we  eigenvalues only 
   ! lworkk = 5*nst + max(3*block,block*(np+1))+1 
   !  if also eigenvectors 
    lworkk =  max( 1 + 6*nst + 2*np*nq, 3*nst + max( block*( np+1 ), 3*block)) + 2*nst
   allocate(Z(lld,lld), Aloc(lld,lld),workk(lworkk), wrk(np)) ! allocate memory to construct the full Hamiltonian matrix, j operator matrix for the calculated number of states in the Sz=0 sector 
      do local_i = 1 , np
        do local_j = 1 , nq
           ! Determine the global indicies (i,j) from the local indices   (local_i,local_j)
           i = indxl2g(local_i,block,myrow,0,nprow)
       j = indxl2g(local_j,block,mycol,0,npcol)
           ! Compute Hmatc(i,j) directly
           if (i == j) then 
           Aloc(local_i,local_j) = real(AD(i))
       else 
       Aloc(local_i, local_j) = 0.d0  ! Initialize to zero 
           do ih = row_ptr(i),row_ptr(i+1) - 1
          ij = col_ind(ih)
          isig = sign(1,col_ind_oper(ih))
              if (ij == j) then 
          if (isig == 1) then 
          Aloc(local_i,local_j) = Aloc(local_i,local_j) + 0.5*J_int
          else 
          Aloc(local_i,local_j) = Aloc(local_i,local_j) - 0.5*isig*J_int
              end if 
          end if 
           end do 
           end if 
        end do 
      end do 
   call pdsyev("v","u",nst,Aloc,1,1,descAloc,W,Z,1,1,descZ,workk,lworkk,info)
   if(myrank ==0) then 
   write(0,*) "info pdsyev", info 
   end if 
   if(myrank == 0) then
        write(0,*) "First and last eigenvalues :"
        write(0,"(6f5.2)") W(1),W(2),W(3),W(nst-2),W(nst-1),W(nst)
   write(0,*) "info pdsyev", info 
   end if     
   allocate(Zglobal(nst,nst)) ! global matrix to store all eigenvectors 
   call pdgemr2d(nst,nst, Z,1,1,descz, Zglobal, 1,1, descZglobal,ictxt)


   if(myrank == 0) then 
   deallocate(Zglobal)
   end if
    deallocate (Z)
    call blacs_gridexit(ictxt)
    call MPI_FINALIZE(info)

编译命令

mpiifx problem.f90 -qmkl=cluster
mpirun -np 16 ./a.out

错误信息

cannot allocate memory, aborted xxmr2d: out of memory

解决方案

1. 限制全局矩阵的分配范围

原代码中所有MPI进程都执行了allocate(Zglobal(nst,nst)),但只有rank=0进程需要存储全局特征向量矩阵。修改为仅在主进程分配:

if(myrank == 0) then
  allocate(Zglobal(nst,nst)) ! 仅主进程分配全局矩阵
end if

原因:当N=30000时,单个双精度Zglobal矩阵占用约7GB内存,16个进程同时分配会占用112GB,加上其他计算内存直接触发OOM。

2. 修正全局矩阵的描述符参数

原代码中descZglobal的块大小设为nst,导致ScaLAPACK尝试按整个矩阵块传输,瞬时内存压力极大。改为和descZ一致的块大小block,并仅在主进程初始化有效描述符:

! 初始化全局矩阵描述符
if(myrank == 0) then
  call DESCINIT(descZglobal, nst, nst, block, block, 0, 0, ictxt, nst, info)
else
  ! 其他进程初始化空描述符避免错误
  call DESCINIT(descZglobal, 0, 0, block, block, 0, 0, ictxt, 1, info)
end if

原因:按小块传输可以降低单进程的瞬时内存占用,避免一次性申请大量内存。

3. 分批次传输特征向量(针对超大N场景)

如果N超过40000,即使主进程单独分配Zglobal也会占用过多内存,可以分批次传输特征向量:

  • 每次传输K列特征向量到主进程
  • 主进程处理完该批次后释放内存,再传输下一批
  • 示例伪代码:
if(myrank == 0) then
  allocate(Zbatch(nst, K)) ! K为批次大小,比如1000
end if

do col_start = 1, nst, K
  col_end = min(col_start + K - 1, nst)
  call pdgemr2d(nst, col_end-col_start+1, Z, 1, col_start, descZ, &
                Zbatch, 1, 1, descZbatch, ictxt)
  ! 处理Zbatch中的特征向量
end do

if(myrank == 0) then
  deallocate(Zbatch)
end if

4. 内存预留与监控

  • 计算主进程的内存需求:双精度矩阵内存= NN8字节,确保主进程有足够剩余内存(比如预留20GB以上给系统和其他计算)
  • 运行前用free -h查看节点内存状态,避免其他进程占用内存

内容的提问来源于stack exchange,提问作者FortranZT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:01:04