2011-12-21 2 views
0

세그멘테이션 오류, 잘못된 종료 오류와 충돌하는 하이브리드 mpi-openmp 코드가 있습니다. mpif90/ifort를 사용하여 컴파일하고 mpich2를 사용합니다. 여기에 내가 오류를 사용하여 얻을 컴파일 라인은 다음과 같습니다ifort mpi-openmp 세분화 오류

mpif90.mpich2 -f90=ifort -DAMD64_LNX -openmp -o jack_openmp.exe laplace.f 

내가 분할 오류 얻을 다른 노드가 포함 된 시스템 파일을 가리키는 하나 개의 노드에서 실행하는 경우,이 명령을 사용하여

===================================================================================== 
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES 
= EXIT CODE: 11 
= CLEANING UP REMAINING PROCESSES 
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES 
===================================================================================== 
APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11) 

그러나 특정 노드 (node1)에서이 파일을 실행하고 머신 파일에 "node1"만있는 경우 노드 당 적절한 양의 스레드를 사용하여 예상대로 실행됩니다 (예 : "node1"이 나열된 경우). 기계 파일에서 두 번, mpiexec 명령은 "mpiexec -np 2 ..."와 같음).

"-openmp"를 연결하는 대신 두 번째로 "-liomp5"를 연결합니다. 이렇게하면 코드가 노드 전체 에서조차 컴파일되어 실행됩니다. 그러나 스레드 된 의미로 실행되지는 않습니다. "omp_get_num_threads"는 노드 당 8 개의 스레드를 반환하지만 (정확한) 머신 파일에 나열된 노드 당 하나의 스레드 만 실행하므로 실제 스레딩을 수행하지 않습니다.

필자는 언급 된대로 최신 ifort 컴파일러 (12.1.2)와 mpich2를 사용하고 있습니다. 스택 크기는 무제한이며 "ulimit -a"를 통해 확인되고 무제한으로 표시됩니다.

laplace.f 파일의 소스 코드는 다음과 같습니다 컴파일에 링크 된 -liomp5를 실행하는 경우

 program lpmlp 
     include 'mpif.h' 
     include "omp_lib.h" 

     integer imax,jmax,im1,im2,jm1,jm2,it,itmax 
     parameter (imax=10001,jmax=10001) 
     parameter (im1=imax-1,im2=imax-2,jm1=jmax-1,jm2=jmax-2) 
     parameter (itmax=100) 
     real*8 u(imax,jmax),du(imax,jmax),umax,dumax,tol,pi 
     parameter (umax=10.0,tol=1.0e-6,pi=3.14159) 
! Additional MPI parameters 
     integer istart,iend,jstart,jend 
     integer size,rank,ierr,istat(MPI_STATUS_SIZE),mpigrid,length 
     integer grdrnk,dims(1),gloc(1),up,down,isize,jsize 
     integer ureq,dreq 
     integer ustat(MPI_STATUS_SIZE),dstat(MPI_STATUS_SIZE) 
     real*8 tstart,tend,gdumax 
     logical cyclic(1) 
     real*8 uibuf(imax),uobuf(imax),dibuf(imax),dobuf(imax) 
! OpenMP parameters 
     integer nthrds,nthreads  

! Initialize 
     call MPI_INIT_THREAD(MPI_THREAD_FUNNELED,IMPI_prov,ierr) 
     call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr) 
     call MPI_COMM_SIZE(MPI_COMM_WORLD,size,ierr) 
! 1D linear topology 
     dims(1)=size 
     cyclic(1)=.FALSE. 
     call MPI_CART_CREATE(MPI_COMM_WORLD,1,dims,cyclic,.true.,mpigrid 
    +  ,ierr) 
     call MPI_COMM_RANK(mpigrid,grdrnk,ierr) 
     call MPI_CART_COORDS(mpigrid,grdrnk,1,gloc,ierr) 
     call MPI_CART_SHIFT(mpigrid,0,1,down,up,ierr) 
     istart=2 
     iend=imax-1 
     jsize=jmax/size 
     jstart=gloc(1)*jsize+1 
     if (jstart.LE.1) jstart=2 
     jend=(gloc(1)+1)*jsize 
     if (jend.GE.jmax) jend=jmax-1 
     nthrds=OMP_GET_NUM_PROCS() 
     print*,"Rank=",rank,"Threads=",nthrds 
     call omp_set_num_threads(nthrds) 

!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(i,j) 
! Initialize -- done in parallel to force "first-touch" distribution 
! on ccNUMA machines (i.e. O2k) 
!$OMP DO 
     do j=jstart-1,jend+1 
     do i=istart-1,iend+1 
      u(i,j)=0.0 
      du(i,j)=0.0 
     enddo 
     u(imax,j)=umax*sin(pi*float(j-1)/float(jmax-1)) 
     enddo 
!$OMP END DO 
!$OMP END PARALLEL 

! Main computation loop 
     call MPI_BARRIER(MPI_COMM_WORLD,ierr) 
     tstart=MPI_WTIME() 
     do it=1,itmax 
! We have to keep the OpenMP and MPI calls segregated... 
     call omp_set_num_threads(nthrds) 

!$OMP PARALLEL DEFAULT(SHARED) PRIVATE(i,j) 
!$OMP MASTER 
     dumax=0.0 
!$OMP END MASTER 
!$OMP DO REDUCTION(max:dumax) 
     do j=jstart,jend 
      do i=istart,iend 
       !nthreads = OMP_GET_NUM_THREADS() 
       !print*,"Jack",rank,nthreads,nthrds 
       du(i,j)=0.25*(u(i-1,j)+u(i+1,j)+u(i,j-1)+u(i,j+1))-u(i,j) 
       dumax=max(dumax,abs(du(i,j))) 
      enddo 
     enddo 
!$OMP END DO 
!$OMP DO 
     do j=jstart,jend 
      do i=istart,iend 
       u(i,j)=u(i,j)+du(i,j) 
      enddo 
     enddo 
!$OMP END DO 
!$OMP END PARALLEL 
! Compute the overall residual 
     call MPI_REDUCE(dumax,gdumax,1,MPI_REAL8,MPI_MAX,0 
    +  ,MPI_COMM_WORLD,ierr) 

! Send phase 
     if (down.NE.MPI_PROC_NULL) then 
      j=1 
      do i=istart,iend 
       dobuf(j)=u(i,jstart) 
       j=j+1 
      enddo 
      length=j-1 
      call MPI_ISEND(dobuf,length,MPI_REAL8,down,it,mpigrid, 
    +   dreq,ierr) 
     endif 
     if (up.NE.MPI_PROC_NULL) then 
      j=1 
      do i=istart,iend 
       uobuf(j)=u(i,jend) 
       j=j+1 
      enddo 
      length=j-1 
      call MPI_ISEND(uobuf,length,MPI_REAL8,up,it,mpigrid, 
    +   ureq,ierr) 
     endif 
! Receive phase 
     if (down.NE.MPI_PROC_NULL) then 
      length=iend-istart+1 
      call MPI_RECV(dibuf,length,MPI_REAL8,down,it, 
    +   mpigrid,istat,ierr) 
      call MPI_WAIT(dreq,dstat,ierr) 
      j=1 
      do i=istart,iend 
       u(i,jstart-1)=dibuf(j) 
       j=j+1 
      enddo 
     endif 
     if (up.NE.MPI_PROC_NULL) then 
      length=iend-istart+1 
      call MPI_RECV(uibuf,length,MPI_REAL8,up,it, 
    +   mpigrid,istat,ierr) 
      call MPI_WAIT(ureq,ustat,ierr) 
      j=1 
      do i=istart,iend 
       u(i,jend+1)=uibuf(j) 
       j=j+1 
      enddo 
     endif 
     write (rank+10,*) rank,it,dumax,gdumax 
     if (rank.eq.0) write (1,*) it,gdumax 
     enddo 
     call MPI_BARRIER(MPI_COMM_WORLD,ierr) 
     tend=MPI_WTIME() 
     if (rank.EQ.0) then 
     write(*,*) 'Calculation took ',tend-tstart,'s. on ',size, 
    +  ' MPI processes' 
    +  ,' with ',nthrds,' OpenMP threads per process' 
     endif 
     call MPI_FINALIZE(ierr) 
     stop 
     end 

는 그렇게 볼 수 있습니다 :

call omp_set_num_threads(nthrds) 

는 nthrds = 8 실행 확인 인쇄 문을 통해, 즉시 확인할 때 :

nthreads = OMP_GET_NUM_THREADS() 

결과 n 번째 그러나 컴파일시 -openmp (동일한 노드에서 시작하여 실행이 시작된 컴퓨터 파일의 모든 노드)에서 링크 할 때 완료되면 nthreads = 8이됩니다.

headhode 이름이 더 길어서 다음과 같이 말합니다.

===================================================================================== 
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES 
= EXIT CODE: 11 
= CLEANING UP REMAINING PROCESSES 
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES 
===================================================================================== 
[proxy:0:[email protected]] HYD_pmcd_pmip_control_cmd_cb (./pm/pmiserv/pmip_cb.c:906): assert (!closed) failed 
[proxy:0:[email protected]] HYDT_dmxu_poll_wait_for_event (./tools/demux/demux_poll.c:77): callback returned error status 
[proxy:0:[email protected]] main (./pm/pmiserv/pmip.c:226): demux engine error waiting for event 
[[email protected]] HYDT_bscu_wait_for_completion (./tools/bootstrap/utils/bscu_wait.c:70): one of the processes terminated badly; aborting 
[[email protected]] HYDT_bsci_wait_for_completion (./tools/bootstrap/src/bsci_wait.c:23): launcher returned error waiting for completion 
[[email protected]] HYD_pmci_wait_for_completion (./pm/pmiserv/pmiserv_pmci.c:189): launcher returned error waiting for completion 
[[email protected]] main (./ui/mpich/mpiexec.c:397): process manager error waiting for completion 

많은 정보가 있지만 너무 많지는 않습니다. 어떤 도움을 주셔서 감사합니다.

+0

내 권장 사항 : (1) MPI와 OpenMP를 섞어서 간단한 코드 샘플 (http://www.slac.stanford.edu/comp/unix/farm/mpi_and_openmp.html)으로 연습을 시작합니다. (2) 디버거를 사용하여 segfault가 정확히 어디에서 발생했는지 확인 했습니까? – steabert

+1

@KyleKanos [메타에 대한이 요청] (http://meta.stackexchange.com/a/226446/158100)으로 인해 태그가 다시 지정되었습니다. 당신이 그것에 불만이라면 거기에 당신의 아이디어를 공유하십시오. – rene

답변

0

Valgrind에서 프로그램을 실행 해보십시오. 먼저 디버그 기호로 -g으로 다시 컴파일하십시오. 이런 식으로 뭔가 아마 도움이 될 것입니다 :

% mpiexec -n 2 valgrind -q ./jack_openmp.exe 

이 프로그램 (뿐 아니라 어떤 임의의 시스템 라이브러리)에 경고/오류를보고하면, 당신은 수정해야 코드에서 버그가 거의 확실있다. 표시된 스택 추적을보고 왜 Valgrind가 불평하는지 파악하십시오.

+0

결과의 업데이트. 많은 문제 해결 후에 선언 된 정적 배열의 크기에 민감하다는 것을 발견했습니다. 정적 배열이 작 으면 코드가 잘 실행됩니다. 코드가 너무 크면 위의 홀수 세그멘테이션 오류로 인해 코드가 충돌합니다. 예제 fortran 프로그램의 경우, 매직 넘버는 720입니다. 즉, imax = jmax = 720이면 코드가 올바르게 완료됩니다. imax = jmax> = 721이면 코드가 seg 결함과 충돌합니다. – jackd

+0

직감으로 정적 배열을 동일한 크기로 재구성했지만 동적으로 할당되고 배열이 얼마나 큰지 완벽하게 작동합니다. 나는 정적으로 할당 된 배열과 동적으로 할당 된 배열을 처리하는 방법의 차이를 잘 이해하지 못하고 있지만 문제의 핵심으로 보인다. 이 코드는 훨씬 큰 코드의 테스트 사례 일 뿐이므로 내 문제는 해결되지 않습니다 (단순히 동적 할당으로 다시 수정). 나는 여전히 컴파일러 및/또는 우분투 설정을 변경하여 작동하도록해야합니다. – jackd

1

OpenMP 스레드 스택 크기가 너무 작을 수 있습니다. 큰 크기의 OMP_STACKSIZE 설정을 시도 했습니까?

% export OMP_STACKSIZE=512m # may be another value: 32m, 64m, 128m, 256m ... 

각 OpenMP 스레드는 개인 스택 메모리를 사용하며 기본 스택 크기는 IA-32에서는 2MB이고 Intel64 아키텍처에서는 4MB입니다.