2016-08-04 3 views
0

Я реализовал простой параллельный решатель уравнения Пуассона с MPI, чтобы ознакомиться с библиотекой MPI. Я разработал код для работы с неопределенным количеством процессоров (в том числе всего с 1).Код застревает при решении уравнения Пуассона с MPI

Код работает и дает хорошие результаты при работе на 1 или 2 процессорах. Тем не менее, он застревает на звонках mpi_send и mpi_recv с 4 процессорами. Поэтому я ожидаю, что моя реализация обмена призракными точками неверна.

Поскольку код слишком большой, чтобы включить здесь, я только включил схему Якоби и обмен данными:

do iter=1,max_iter                      
    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    ! Initial guess, on interior points only               
    Ujacob(min_x+1:max_x-1) = 0._dp                 
    Ujacob_all(0:grid_nx-1) = 0._dp                 

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    ! Store solution vector from last iteration              
    Uold (:) = Ujacob (:)                  
    Uold_all(:) = Ujacob_all(:)                  

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    ! Jacobi scheme                     
    do ii=min_x+1,max_x-1                    
     !Ujacob(ii) = 0.5_dp * (Uold (ii-1) + Uold (ii+1) - grid_delta_x**2 * Urhs(ii))    
    end do                        

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    ! Gather Ujacob vector                    
    call mpi_allgather(Ujacob(0:proc_nx-1), proc_nx, mpi_float,       &    
        & Ujacob_all,   proc_nx, mpi_float, mpi_comm_world, ierror)    

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    ! Compute error and check if less than tolerance value            
    error = sqrt((sum(Ujacob_all - Uold_all)**2)/dble(grid_nx))          

    if(error < error_tol) return                  
    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
    ! Exchange data points                    

    ! Interior processors                   
    if(Xsrc /= -1 .AND. Xdes /= -1) then 
     call mpi_send(Ujacob(  0), 1, mpi_float, Xsrc, 200, mpi_comm_world, ierror)   
     call mpi_send(Ujacob(proc_nx-1), 1, mpi_float, Xdes, 100, mpi_comm_world, ierror)   

     call mpi_recv(Ujacob( -1), 1, mpi_float, Xsrc, 100, mpi_comm_world, stat, ierror)  
     call mpi_recv(Ujacob(proc_nx), 1, mpi_float, Xdes, 200, mpi_comm_world, stat, ierror) 
    ! First processor                    
    elseif(Xsrc == -1) then                  
     call mpi_send(Ujacob(proc_nx-1), 1, mpi_float, Xdes, 100, mpi_comm_world, ierror)   
     call mpi_recv(Ujacob(proc_nx ), 1, mpi_float, Xdes, 200, mpi_comm_world, stat, ierror) 
    ! Last processor                    
    elseif(Xdes == -1) then                 
     call mpi_send(Ujacob(0), 1, mpi_float, Xsrc, 200, mpi_comm_world, ierror)     
     call mpi_recv(Ujacob(-1), 1, mpi_float, Xsrc, 100, mpi_comm_world, stat, ierror)   
    end if                           
end do 

Xsrc и Xdes устанавливаются следующим образом:

!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    ! Setting the source and destination neighbors of each processor        
    if(myid == 0) then                    
     Xsrc = -1                     
     Xdes = myid + 1                   
    elseif(myid == nprocs-1) then                 
     Xsrc = myid -1                    
     Xdes = -1                     
    else                       
     Xsrc = myid - 1                   
     Xsrc = myid + 1                   
    end if 

Кроме того, я проверил, что процессор ранга 0 и nprocs-1 действительно соответствуют левым и правым ограниченным процессорам.

Я проверил, что метки хорошо установлены. Кроме того, не стесняйтесь комментировать все, что, по вашему мнению, может быть улучшено.

+1

Я думаю, что может быть полезно посмотреть, как вы устанавливаете 'Xsrc' и' Xdes'. –

+0

@ d_1999 Да, вы правы, см. Править – solalito

+0

Ваш обмен ореолом концептуально ошибочен, поскольку вы полагаетесь на буферизацию «MPI_SEND», что может быть не всегда так. Используйте 'MPI_SENDRECV' для отправки и получения в одно и то же время без блокировки. Кроме того, не используйте такую ​​сложную логику для отправки и получения. Просто используйте 'MPI_PROC_NULL' вместо' -1' для несуществующих соседей пограничных рангов и всегда выполняйте sendrecv в обоих направлениях. Отправка на 'MPI_PROC_NULL' или получение от него - нет-op. –

ответ

3

@Hristo правильно, что ваш код концептуально ошибочен в принципе. Однако почти каждая реализация MPI будет буферизовать MPI_Send для сообщения, содержащего один реальный (хотя, конечно, это не гарантируется), так что это не проблема с вашим кодом.

Я думаю, что вы несовпадающие свои метки - краевые случаи должны иметь бирки наоборот:

elseif(Xsrc == -1) then                  
     call mpi_send(Ujacob(proc_nx-1), 1, mpi_float, Xdes, 200, mpi_comm_world, ierror)   
     call mpi_recv(Ujacob(proc_nx ), 1, mpi_float, Xdes, 100, mpi_comm_world, stat, ierror) 
    ! Last processor                    
    elseif(Xdes == -1) then                 
     call mpi_send(Ujacob(0), 1, mpi_float, Xsrc, 100, mpi_comm_world, ierror)     
     call mpi_recv(Ujacob(-1), 1, mpi_float, Xsrc, 200, mpi_comm_world, stat, ierror)   
    end if  

Несколько других замечаний по коду:

  • это очень неэффективно, чтобы вычислить ошибку term with allgather: вы должны суммировать только локальные элементы, а затем вычислить глобальную ошибку с помощью MPI_Allreduce;
  • вы должны использовать MPI_REAL, а не MPI_FLOAT для кода Fortran;
  • Я не вижу, как наш код может работать на одном процессе - здесь процесс выполнит первое предложение elseif, а затем попробует и отправит несуществующий ранг.

После того как вы подтвердили правильность ваших тегов, вы должны исправить проблемы, отмеченные @Hristo.

+0

Собственно теги были правы. Основная проблема была связана с опечаткой при определении 'Xsrc' и' Xdes'. Я исправил его вместе с другими неэффективными проблемами, которые у меня были - см. Выше комментарии. Однако, у меня есть вопрос. Что вы подразумеваете под «почти каждая реализация MPI будет буферизовать« MPI_SEND »для сообщения, содержащего один реальный? – solalito

+0

Проблема заключается в том, является ли отправка синхронной (т. Е. Не завершена до тех пор, пока не будет отправлен соответствующий прием) или асинхронно (завершается независимо от есть ли подходящий прием) .Ssend гарантированно синхронный & Bsend гарантированно асинхронный. Однако Send может быть либо. Это был тот момент, который делал @HristoIliev - если Send является синхронным, тогда ваш код будет тупиковым, поскольку все процессы отправляются, и никто не получает Асинхронная отправка требует создания копии и доставки позже. Для небольших сообщений MPI обычно берет копию, а для больших сообщений не будет места, поэтому она использует синхронную отправку. –