Menggunakan MPI_Irecv dan MPI_Isend dalam loop for

Saya memiliki masalah dengan MPI_Isend dan MPI_Irecv. Saya sedang mengerjakan matriks ketetanggaan dari sebuah grafik, yang didistribusikan berdasarkan baris. Kita dapat berasumsi bahwa setiap prosesor berisi satu baris. Untuk setiap pasangan indeks (i,j) saya perlu mengirim dan menerima 2 bilangan bulat. Pada dasarnya, saya perlu menerima beberapa informasi lain dari baris lain untuk melakukan perhitungan. Saya baru di MPI, dan ini masuk ke loop tak terbatas, saya bahkan tidak yakin apakah ini cara yang tepat untuk menggunakan MPI_Isend atau MPI_Irecv dalam loop for, juga sebagai tempat untuk menunggu.

Sebagai contoh, Asumsikan kita mempunyai graf dengan 6 simpul, sehingga matriks ketetanggaan (adjMatrix) adalah matriks 6*6, kita juga mempunyai matriks 6*2 untuk beberapa informasi lainnya, dan terakhir, kita mendistribusikan graf tersebut data di antara 6 prosesor. Karena itu:

          |0  20 16 0  6  0 |      |0  1|
          |20 0  0  19 0  6 |      |1  1|
addMatrix=|16 0  0  0  12 0 |    M=|2  1|
          |0  19 0  0  0  12|      |3  1|
          |6  0  12 0  0  9 |      |0  0|
          |0  6  0  12 9  0 |      |1  0|

Kami mendistribusikan matriks sebagai berikut:

P0:       |0  20 16 0  6  0 |      |0  1|

P1:       |20 0  0  19 0  6 |      |1  1|

P2:       |16 0  0  0  12 0 |      |2  1|

P3:       |0  19 0  0  0  12|      |3  1|

P4:       |6  0  12 0  0  9 |      |0  0|

P5:       |0  6  0  12 9  0 |      |1  0|

Sekarang, setiap prosesor perlu memperbarui porsinya sebesar adjMatrix. Untuk melakukannya, mereka memerlukan informasi dari beberapa bagian matriks M, yang ada di prosesor lain. Misalnya, untuk P0 memperbarui indeks (0,1) yaitu 20, ia perlu memiliki akses ke baris 1 dari matriks M yaitu {1,1}. Karena itu:

P1 harus mengirim MLocal[0][0]=1 dan MLocal[0][1]=1 ke P0 di mana P0 menerimanya masing-masing sebagai M_j0 dan M_j1.

Dan

P0 harus mengirim MLocal[0][0]=0 dan MLocal[0][1]=1 ke P1 di mana P1 menerimanya masing-masing sebagai M_j0 dan M_j1.

    for(int i=0;i<rows;i++){
            for (int j=0; j<n; j++)
            {
                int M_j0,M_j1;
                MPI_Isend(&MLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &send_request0);
                MPI_Isend(&MLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &send_request1);
                MPI_Irecv(&M_j0, 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &recv_request0);
                MPI_Irecv(&M_j1, 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &recv_request1);
                //MPI_Wait(&send_request0, &status);
                //MPI_Wait(&send_request1, &status);
                MPI_Wait(&recv_request0, &status);
                MPI_Wait(&recv_request1, &status);

                 // Do something ...
            }
        }

Kemudian dengan saran GillesGouaillardet, saya mengubah 4 MPI_Isend dan MPI_Irecv menjadi:

    MPI_Sendrecv(&MoatsLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, &M_j0,1, MPI_INT, my_rank, my_rank+i*n+j+0, MPI_COMM_WORLD, &status);
    MPI_Sendrecv(&MoatsLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, &M_j1,1, MPI_INT, my_rank, my_rank+i*n+j+1, MPI_COMM_WORLD, &status);

Tapi tetap saja, ini masuk ke dalam lingkaran tak terbatas.

MEMPERBARUI:

Saya memperbarui kodenya, sebagian masalahnya adalah karena peringkat prosesor dan pencocokan tag. Saya memperbaiki bagian itu tetapi tetap saja rawan kebuntuan, yang menurut saya saya tahu di mana masalahnya. Dan mungkin tidak bisa menyelesaikannya. Jika saya memiliki jumlah prosesor yang cukup, untuk mendistribusikan setiap baris ke prosesor, yaitu n=p, itu tidak akan menjadi masalah. Namun permasalahannya dimana jumlah processor kurang dari n, maka alirannya tidak lancar melalui diagonal utama Saya jelaskan melalui contoh, misalkan kita mempunyai 4 processor dan n=6. Asumsikan inilah distribusinya:

P0:       |0  20 16 0  6  0 |      |0  1|

P1:       |20 0  0  19 0  6 |      |1  1|
          |16 0  0  0  12 0 |      |2  1|

P2:       |0  19 0  0  0  12|      |3  1|

P3:       |6  0  12 0  0  9 |      |0  0|
          |0  6  0  12 9  0 |      |1  0|

Inilah yang terjadi melalui loop.

Iterasi pertama:

P0 mengirim dan menerima ke/dari informasi P1 untuk (0,1):"20" dan tunggu(selesai)

P1 mengirim dan menerima ke/dari informasi P0 untuk (1,0):"20" dan tunggu(selesai)

P2 mengirim dan menerima ke/dari informasi P1 untuk (3,1):"19" dan tunggu

P3 mengirim dan menerima ke/dari informasi P0 untuk (4,1):"6" dan tunggu

Iterasi kedua:

P0 mengirim dan menerima ke/dari informasi P1 untuk (0,2):"16" dan tunggu

P1 mengirim dan menerima ke/dari informasi P2 untuk (1,3):"19" dan tunggu(selesai)

P2 menunggu P1 (3,1):"19" lalu terima saja dan selesai!

P3 menunggu P0 untuk (4,1):"6" dan tunggu

Iterasi ketiga:

P0 menunggu P1 untuk (0,2):"16"

P1 mengirim dan menerima ke/dari informasi P3 untuk (1,5):"19" dan tunggu

P2 mengirim dan menerima ke/dari informasi P3 untuk (3,5):"12" dan tunggu

P3 menunggu P0 untuk (4,1):"6"

Iterasi keempat:

P0 menunggu P1 untuk (0,2):"16"

P1 menunggu P3 untuk (1,5):"19"

P2 menunggu P3 untuk (3,5):"12"

P3 menunggu P0 untuk (4,1):"6"

Sekarang, semua menunggu satu sama lain, saya rasa tidak ada cara untuk menyelesaikannya. Solusi yang disarankan ptb mungkin berhasil, saya akan mencobanya.

Namun, ide lain apa pun dihargai!


person Sarah    schedule 04.04.2018    source sumber
comment
Anda dapat menggunakan array yang terdiri dari 4 permintaan, lalu MPI_Waitall(4, ...);   -  person Gilles Gouaillardet    schedule 04.04.2018
comment
Anda mungkin juga dapat menggunakan dua MPI_Sendrecv()   -  person Gilles Gouaillardet    schedule 04.04.2018
comment
@GillesGouaillardet Saya melakukan seperti yang Anda sebutkan. Masih memiliki masalah yang sama.   -  person Sarah    schedule 04.04.2018
comment
harap unggah contoh minimal yang dapat direproduksi.   -  person Gilles Gouaillardet    schedule 04.04.2018
comment
@GillesGouaillardet Saya memperbaruinya. Bantuan apa pun dihargai.   -  person Sarah    schedule 04.04.2018
comment
Ya, itu bukan contoh minimal yang dapat direproduksi   -  person Gilles Gouaillardet    schedule 05.04.2018
comment
juga, apakah Anda mencoba dengan MPI_Waitall(4, ...) ? hal ini seharusnya mengurangi kemungkinan terjadinya kebuntuan.   -  person Gilles Gouaillardet    schedule 05.04.2018
comment
@GillesGouaillardet ya, begitulah yang saya lakukan saat ini, saya menemukan di mana masalah yang menyebabkan rawan kebuntuan, yang menurut saya tidak ada cara untuk menyelesaikannya. Saya memperbarui pertanyaan saya.   -  person Sarah    schedule 05.04.2018


Jawaban (2)


Ada beberapa masalah dengan kode yang Anda posting

  1. Setiap prosesor akan melakukan loop melalui rows. Namun dalam uraian Anda, baris-baris tersebut didistribusikan di antara prosesor jadi ini mungkin merupakan kesalahan.
  2. Tujuan dan sumber pengiriman dan penerimaan sama. Jadi jika Anda mempertimbangkan kasus ketika j=0, MPI_Isend(...,j,...) berarti setiap peringkat akan mengirimkan sesuatu ke proses root. Ini diikuti dengan panggilan ke MPI_IRecv(...,j,...), MPI_Wait yang artinya setiap proses akan menunggu pengiriman dari proses root yang tidak pernah datang.
  3. Panggilan MPI_SendRecv memiliki masalah mendasar yang sama

Tantangannya adalah Anda harus mengirim dan menerima panggilan agar sesuai. Salah satu cara untuk melakukannya (belum tentu yang paling berkinerja) adalah dengan memposting semua pengiriman Anda melalui MPI_Isend dalam satu lingkaran dan kemudian menggunakan MPI_Probe, MPI_Recv untuk memproses setiap peringkat yang diterima (karena jumlah penerimaan adalah jumlah pengiriman yang Anda tahu persis caranya banyak). Contoh kode semu:

int send_count = 0;
for (int j=0; j<n; j++) {
  if (matrix_entry[j] != 0) {
    call MPI_Isend(M_local, 2, MPI_INT, j, 0, ...)
    send_count++;
  }
}
while (send_count) {
  MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, comm, status)
  /* get source from status and then call recv */
  MPI_Recv(M_j01, 2, MPI_INTEGER, status(MPI_SOURCE), ...)
 /* Do something with M_j01 */
 send_count--;
} 
person ptb    schedule 05.04.2018
comment
Terima kasih, Anda benar, peringkat dan tagnya salah, saya perbaiki saja. Namun, saya mempunyai masalah lain yang menyebabkan rawan kebuntuan. Saya memperbarui pertanyaan saya dan memberikan detail lebih lanjut. Ada ide? - person Sarah; 05.04.2018
comment
Anda masih menggabungkan operasi kirim/penerimaan daripada memposting semua pengiriman Anda dan kemudian melanjutkan ke pemrosesan penerimaan. Cara Anda menulisnya, pada dasarnya sinkron/memblokir karena Anda memanggil wait tepat setelah pengiriman. Anda dapat melakukannya dengan cara itu tetapi Anda perlu lebih berupaya mengatur pengiriman/penerimaan agar kompatibel. - person ptb; 06.04.2018

Beberapa saran kecil:

Anda harus selalu ingat bahwa setiap proses bersifat independen.. Tidak ada sinkronisasi antar proses (berharap jika Anda memasang MPI_Barrier).

Saya benar-benar tidak memahami perulangan baris Anda (apakah baris = 6?)

Kemudian semua proses mengeksekusi kodenya.... Artinya: P0,1,2,3,4,5,6 Memanggil sendrecv Anda, semuanya melakukannya 6 kali, karena panggilan tersebut dalam satu lingkaran...

Terakhir: Berapa ukuran matriks yang biasa? Mengirim banyak pesan yang sangat kecil adalah ide yang sangat buruk.

Anda harus merancang algoritme Anda sebagai berikut: 1) Cari tahu data mana yang dibutuhkan proses PX untuk memperbarui semua kolomnya. 2) melakukan komunikasi yang mengumpulkan data ini untuk semua proses 3) Melakukan pembaruan.

person David Daverio    schedule 09.04.2018