Estou tentando implementar paralelização em um código flowsolver para meu Phd, herdei uma subrotina que está enviando dados entre subdomínios predefinidos. A subrotina está enviando dados por meio do comando MPI_Isend e recebendo-os com o comando MPI_Irecv, chamando então um waitall.
(o código ofensivo abaixo:)
! -----------------------------------------------------------
! Definition of instant send/receive passings with barrier at the end
! -----------------------------------------------------------
spos=1 ! Position of the first element to send within send array
do i=1,isize ! loop over the number of exchanging segments
if (nsendseg(i).ne.0) then ! choose only domains with something to send
call MPI_ISend(send(spos),nsendseg(i),MPI_REAL8,i-1,1,MPI_COMM_WORLD,reqs(i),ierr)
spos=spos+nsendseg(i)
end if
enddo
rpos=1
do i=1,isize
if (nrecvseg(i).ne.0) then
call MPI_IRecv(recv(rpos),nrecvseg(i),MPI_REAL8,i-1,MPI_ANY_TAG,MPI_COMM_WORLD,reqs(i+sum(nsendseg)),ierr)
rpos=rpos+nrecvseg(i)
end if
end do
if (irank .eq. 0) print *, reqs
call MPI_Waitall(sum(nsendseg)+sum(nrecvseg),reqs,MPI_STATUSES_IGNORE,ierr)
EDIT ESCLARECENDO o sum(nsendseg)+sum(nrecvseg): Eu "acredito" (eu herdei esse código de um ex-aluno de doutorado que herdou de outro, então há alguns sussurros chineses circulando) que nsendseg representa o número de nós que o segmento (núcleo) vai enviar e para onde. Ou seja, rodando em 10 núcleos, eles são matrizes de 10 inteiros representando os nós compartilhados entre subdomínios em núcleos. De modo que se o segmento 3 compartilha 12 nós com o segmento 1 e 3 com o segmento 7 e nenhum com nenhum outro, nsendseg é (12,0,0,0,0,0,3,0,0,0). o número de nós que qualquer segmento recebe e envia é diferente porque muitos segmentos podem se conectar a um. A ideia aqui é que cada núcleo itere por uma lista de todos os outros núcleos e envie e receba apenas os dados relevantes de cada um.
Este trecho de código aborta com cópias do erro abaixo em alguns ou todos os nós.
Abort(336210451) on node 13 (rank 13 in comm 0): Fatal error in PMPI_Waitall: Request pending due to failure, error stack:
PMPI_Waitall(352): MPI_Waitall(count=28734, req_array=0x18ac060, status_array=0x1) failed
PMPI_Waitall(328): The supplied request in array element 2 was invalid (kind=0)
Minha ideia atual sobre o que está errado aqui é que o array reqs não está tendo identificadores de comunicação passados corretamente. O bloco de texto abaixo é um exemplo do array reqs onde isso "parece" que as sub-rotinas isend ou irecv estão tentando colocar um tipo de dado estranho (reqs é um array de inteiros padrão).
0 -1409286132 0 0 -1409286133 -1409286135
-1409286134 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 -1409286131
0 0 -1409286130 -1409286129 -1409286128 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0
Sei que isso é um pouco imprevisível, porque estou basicamente pedindo para pessoas aleatórias da internet adivinharem o significado de um pedaço de código que alguém que já seguiu em frente escreveu há muito tempo.
Alguém pode ver a origem do meu erro ou, alternativamente, me informar como deve ser um identificador de comunicação mpi ou qualquer outro conselho sábio? Seria muito apreciado. <3
Você precisa inicializar
reqs = MPI_REQUEST_NULL
antes do loop.Esperar por solicitações nulas é válido e imediatamente bem-sucedido. É aceitável ter solicitações nulas no array passado para waitall. O cálculo para o número de solicitações parece estranho. Você não mostrou o tamanho de reqs. Ele deve ser do tamanho 2*isize para a seguinte solução:
A solução sem buracos na matriz de solicitações (o limite superior para o número de solicitações ainda é 2*isize):