使用 scalapack 例程 PDGESV 求解一组线性联立方程 Ax = b 的并行 fortran 代码失败(退出时出现分段错误)。方程组 N 变大。我还没有确定出现问题的 N 的确切值,但是,例如,该代码对于我测试过的所有值都可以完美运行,直到 N=50000,但在 N=94423 时失败。
特别是在调用 scalapack PDGESV 例程期间发生故障(即不是在分配/释放内存时);它进入例程 PDGESV,但不离开此例程。
我正在使用 Intel(R) Xeon(R) CPU E5-1660 v4 @ 3.20GHz 处理器开发具有 148 GB 内存的 Linux Mint 18.3 Sylvia 系统。我正在使用使用 gfortran 的 mpifortran。
我有点相信fortran代码本身没有问题,因为该代码对于N的每个值和进程配置都可以完美运行,我尝试了N = 50000,并以INFO = 0代码退出,表明没有错误有发生了。(我还运行了一个稍微修改过的程序版本,它明确地检查了解矩阵 x* 的残差,即计算的 Ax* - b 并正确地找到了接近零的最大绝对值)。如果矩阵是奇异的存在一些问题,我们当然会观察到从 PDGESV 例程中退出并带有非零 INFO 代码。
机器的内存似乎也足够了;对于问题案例 N=94423,我们只需要 65 GB 内存,而可用的 148 GB 内存,在分配时没有问题(此外,解决相同问题的串行代码,使用 65 GB 内存,运行没有错误)。
我的感觉是,在 mpi 中单个进程可用的内存可能超出默认限制可能会出现一些问题?即也许我只是在编译/运行时缺少一些适当的标志?
我曾尝试使用 'ulimit -s unlimited' 命令,但这并没有解决问题。
我复制下面的fortran代码;这是一个简单的测试程序,1) 为矩阵 A 和向量 b 分配空间,2) 用随机条目填充它们的条目 3) 调用 PDGESV,然后 4) 释放内存。
我在下面列出了我使用的编译/执行命令(使用 mpifortran/gfortran)。
注意我也尝试使用 PGI fortran 编译器,并观察到相同测试用例的相同错误(请参阅下面的错误输出)。
Fortran 代码:
PROGRAM SOLVE_LU
USE MPI
IMPLICIT NONE
INTEGER :: N
DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:,:) :: LOCAL_A
DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:) :: LOCAL_B
INTEGER :: ISTATUS
C FOR LAPACK PDGESV CALL
INTEGER :: INFO, NRHS, IA, JA, IB, JB
INTEGER, ALLOCATABLE, DIMENSION (:) :: IPIV
c FOR READING COMMAND LINE ARGUMENTS
INTEGER :: IARGC, N_COMMAND_ARG
CHARACTER :: ARGV*10
C WE USE FOLLOWING COMMAND LINE ARGUMENTS
C ARG 1 : N (DIMENSION OF PROBLEM)
C ARG 2 : NPROW (NO. OF ROWS OF PROCESSES IN A RECTANGULAR ARRAY)
C ARG 3 : NPCOL (NO. OF COLUMNS OF PROCESSES IN A RECTANGULAR ARRAY)
C ARG 4 : BLACS BLOCK SIZE MB (BLOCKS ARE OF SIZE MB * MB)
C
c FOR PARALLEL PROCESS ARRAY
INTEGER :: NPROW, NPCOL, ICTXT,MYROW, MYCOL, MB, NB, MLOC, NLOC
INTEGER :: IDESCA(9), IDESCB(9)
INTEGER :: IERR
INTEGER :: NUMROC
c for random number seed
INTEGER :: ISEEDSIZE
INTEGER, ALLOCATABLE, DIMENSION ( :) :: SEED
C ----------------------------------------
C ------- EXECUTABLE STATEMENTS -------
C ===============================================
C READ IN COMMAND LINE ARGUMENTS IF PRESENT
N_COMMAND_ARG = iargc()
IF (N_COMMAND_ARG == 2) THEN
WRITE(*,*) 'ILLEGAL NO. OF COMMAND LINE PARAMETERS'
STOP
ENDIF
IF (N_COMMAND_ARG .GE. 1)THEN
CALL GETARG(1,argv)
C WRITE(*,*)'ARGV = ',ARGV
READ (ARGV,'(I10)') N
ELSE
N = 100
ENDIF
IF (N_COMMAND_ARG .GE. 3)THEN
CALL GETARG(2,argv)
READ (ARGV,'(I10)') NPROW
CALL GETARG(3,argv)
READ (ARGV,'(I10)') NPCOL
ELSE
NPROW = 2
NPCOL = 2
ENDIF
IF (N_COMMAND_ARG .GE. 4)THEN
CALL GETARG(4,argv)
READ (ARGV,'(I10)') MB
ELSE
MB = 8
ENDIF
NB = MB
C ==============================================
C INITIALISE THE BLACS PROCESS GRID, FIND DIMENSIONS OF LOCAL
C MATRICES / VECTORS AND ALLOCATE SPACE
CALL SL_INIT(ICTXT, NPROW, NPCOL)
CALL BLACS_GRIDINFO( ICTXT, NPROW, NPCOL, MYROW, MYCOL )
MLOC = NUMROC(N, MB, MYROW, 0, NPROW)
NLOC = NUMROC(N, NB, MYCOL, 0, NPCOL)
IF( MYROW.EQ.0 .AND. MYCOL.EQ.0 )WRITE(*,*)
@ 'WE ARE SOLVING A SYSTEM OF ', N, ' LINEAR EQUATIONS'
WRITE(*,*) 'PROC: ',MYROW, MYCOL,'HAS MLOC, NLOC =', MLOC,NLOC
c ==============================================
C ALLOCATE SPACE FOR MATRIX A AND VECTORS B AND X
WRITE(*,*) 'PROC: ',MYROW, MYCOL,' ALLOCATING SPACE ...'
ALLOCATE ( LOCAL_A(MLOC,NLOC), STAT = ISTATUS )
IF(ISTATUS .NE. 0) THEN
WRITE(*,*)'UNABLE TO ALLOCATE LOCAL_A, PROCESS: ',MYROW,MYCOL
STOP
ENDIF
ALLOCATE ( LOCAL_B(MLOC), STAT = ISTATUS )
IF (ISTATUS /= 0) THEN
WRITE(*,*)
@ ' FAILED TO ALLOCATE SPACE FOR LOCAL_B, PROCESS: ',MYROW,MYCOL
STOP
ENDIF
c BLACS DESCRIPTOR FOR A AND ITS COPY
CALL DESCINIT (IDESCA, N, N, MB, NB, 0, 0,
@ ICTXT, MLOC, IERR)
c BLACS DESCRIPTOR FOR B AND SOLN VECTOR X
CALL DESCINIT (IDESCB, N, 1, MB, 1, 0, 0, ICTXT, MLOC, IERR)
c ==============================================
C FILL ENTRIES OF MATRIX A AND R.H.S. VECTOR B WITH RANDOM ENTRIES
WRITE(*,*)'PROC: ',MYROW, MYCOL,
@ ' CONSTRUCTING MATRIX A AND RHS VECTOR B ...'
CALL RANDOM_SEED
CALL RANDOM_SEED ( SIZE = ISEEDSIZE ) ! GET SIZE OF SEED ARRAY
ALLOCATE ( SEED(1:ISEEDSIZE) )
CALL RANDOM_SEED ( GET = SEED )
SEED(1) = SEED(1) + NPCOL*MYROW + MYCOL ! ENSURES DIFFERENT SEED
! FOR EACH PROCESS
CALL RANDOM_SEED ( PUT = SEED )
CALL RANDOM_NUMBER(LOCAL_B)
CALL RANDOM_NUMBER(LOCAL_A)
c ==============================================
C CALL LAPACK LU SOLVER ROUTINE
WRITE(*,*)'PROC: ',MYROW, MYCOL,
@ 'NOW SOLVING SYSTEM AX = B USING SCALAPACK PDGESV ..'
ALLOCATE ( IPIV(MLOC + MB), STAT=ISTATUS )
IF(ISTATUS /= 0) THEN
WRITE(*,*)'UNABLE TO ALLOCATE IPIV, PROCESS: ',MYROW,MYCOL
STOP
ENDIF
IA = 1
JA = 1
IB = 1
JB = 1
NRHS = 1
INFO = 0
CALL PDGESV(N, NRHS, LOCAL_A, IA, JA, IDESCA, IPIV,
@ LOCAL_B, IB, JB, IDESCB, INFO )
IF( MYROW.EQ.0 .AND. MYCOL.EQ.0 ) THEN
WRITE(*,*)
WRITE(*,*) 'INFO code returned by PDGESV = ', INFO
WRITE(*,*)
END IF
c ==============================================
C DEALLOCATE MEMORY
DEALLOCATE(LOCAL_A, STAT=ISTATUS)
IF(ISTATUS /= 0) THEN
WRITE(*,*)'UNABLE TO DEALLOCATE '
STOP
ENDIF
DEALLOCATE(LOCAL_B, STAT=ISTATUS)
IF(ISTATUS /= 0) THEN
WRITE(*,*)'UNABLE TO DEALLOCATE '
STOP
ENDIF
DEALLOCATE(IPIV, STAT=ISTATUS)
IF(ISTATUS /= 0) THEN
WRITE(*,*)'UNABLE TO DEALLOCATE '
STOP
ENDIF
c ===================================================
c RELEASE BLACS CONTEXT
CALL BLACS_GRIDEXIT(ictxt)
CALL BLACS_EXIT(0)
END PROGRAM SOLVE_LU
我用以下代码编译上面的代码: mpifort -Wall -mcmodel=medium -static-libgfortran -m64 /opt/openblas/lib/libopenblas.a /usr/local/lib/libscalapack.a /opt/openblas/lib/libopenblas.a -lm -lpthread -lgfortran -lm -lpthread -lgfortran -o para.exe solve_by_lu_parallelmpi_simple_light.for /opt/openblas/lib/libopenblas.a /usr/local/lib/libscalapack.a /opt/openblas/lib/libopenblas.a -lm -lpthread -lgfortran -lm -lpthread -lgfortran
它不会产生错误或警告,并使用(例如)运行它:
mpirun -n 4 ./para.exe 944 2 2 32 > DUMP05
在这里,我们使用块大小为 32 的 2x2 BLACS 进程阵列来求解 944 个 eqns 的系统。
对于这个小 N 案例,我们得到(成功运行)输出:
我们正在求解一个由 944 个线性方程组成的系统
过程:0 0 有 MLOC,NLOC = 480 480
过程:0 0 分配空间...
过程:1 0 具有 MLOC,NLOC = 464 480
过程:1 0 分配空间...
PROC: 0 0 构造矩阵 A 和 RHS 向量 B ...
PROC: 1 0 构造矩阵 A 和 RHS 向量 B ...
过程:1 1 具有 MLOC,NLOC = 464 464
PROC: 1 1 分配空间...
PROC: 1 1 构造矩阵 A 和 RHS 向量 B ...
过程:0 1 有 MLOC,NLOC = 480 464
PROC: 0 1 分配空间...
PROC: 0 1 构造矩阵 A 和 RHS 向量 B ...
PROC: 0 0 现在解决系统 AX = B 使用 SCALAPACK PDGESV
.. PROC: 1 0 现在解决系统 AX = B 使用 SCALAPACK PDGESV
.. PROC: 1 1 现在解决系统 AX = B 使用 SCALAPACK PDGESV
.. PROC: 0 1 现在解决系统 AX = B 使用 SCALAPACK PDGESV
..
PDGESV 返回的 INFO 代码 = 0
到目前为止,一切都很好。但是,改为运行:
mpirun -n 4 ./para.exe 94423 2 2 32 > DUMP06
产生以下错误(注意这样的执行需要 65 GB 内存,在我的机器上大约需要 45 分钟):
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
程序收到信号 SIGSEGV:分段错误 - 无效的内存引用。
此错误的回溯:
此错误的回溯:
此错误的回溯:
此错误的回溯:
此错误的回溯:
此错误的回溯:
此错误的回溯:
此错误的回溯:
出于某种原因,没有打印回溯信息,但是使用 PGI fortran 编译器(在运行 red hat linux 7.3 的不同机器上)运行相同的代码会产生以下输出失败:
[sca1993:113193] * 处理接收到的信号 *
[sca1993:113193] 信号:分段错误 (11)
[sca1993:113193] 信号代码:地址未映射 (1)
[sca1993:113193] 地址失败:0x2b8c5a036390
[sca1993:113193] [0] /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../.. /lib64/libpthread.so.0(+0xf5d0)[0x2b900528c5d0 ]
[sca1993:113193] [1] /usr/local/pgi/linux86-64/17.7/lib/libblas.so.0(+0x280c950)[0x2b9003acc950]
[sca1993:113193] [2] /usr/local/pgi/linux86-64/17.7/lib/libblas.so.0(daxpy_k_HASWELL+0x7f)[0x2b9003acc54f]
[sca1993:113193] [3] /usr/local/pgi/linux86-64/17.7/lib/libblas.so.0(dger_k_HASWELL+0xd5)[0x2b9003ad6635]
[sca1993:113193] [4] /usr/local/pgi/linux86-64/17.7/lib/libblas.so.0(dger_+0x21f)[0x2b90013d9f5f]
[sca1993:113193] [5] ./para_try.exe[0x446e70]
[sca1993:113193] [6] ./para_try.exe[0x41b4ad]
[sca1993:113193] [7] ./para_try.exe[0x4071e1]
[sca1993:113193] [8] ./para_try.exe[0x406b39]
[sca1993:113193] [9] ./para_try.exe[0x404ba6]
[sca1993:113193] [10] ./para_try.exe[0x403654]
[sca1993:113193] [11] /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/libc.so.6(__libc_start_main+0xf5)[ 0x2b9005cb83d5]
[sca1993:113193] [12] ./para_try.exe[0x403549]
[sca1993:113193] * 错误消息结束 *
如果有人有任何建议,我将不胜感激。非常感谢,丹。