Pertama, jawaban yang tepat tergantung pada: (1) penggunaan, yaitu argumen input fungsi, (2) kualitas dan detail implementasi MPI, dan (3) perangkat keras yang Anda gunakan. Seringkali, (2) dan (3) terkait, seperti ketika vendor perangkat keras mengoptimalkan MPI untuk jaringan mereka.
Secara umum, menggabungkan kolektif MPI lebih baik untuk pesan yang lebih kecil, karena biaya awal dapat nontrivial dan sinkronisasi yang disyaratkan oleh memblokir kolektif harus diminimalkan jika ada variasi dalam menghitung waktu antara panggilan. Untuk pesan yang lebih besar, tujuannya adalah meminimalkan jumlah data yang dikirim.
Sebagai contoh, secara teori, MPI_Reduce_scatter_block
harus lebih baik daripada MPI_Reduce
diikuti oleh MPI_Scatter
, meskipun yang pertama sering diterapkan dalam hal yang terakhir, sehingga tidak ada keuntungan nyata. Ada korelasi antara kualitas implementasi dan frekuensi penggunaan di sebagian besar implementasi MPI, dan vendor jelas mengoptimalkan fungsi-fungsi yang diperlukan oleh kontrak mesin ini.
Di sisi lain, jika seseorang menggunakan Blue Gene, melakukan MPI_Reduce_scatter_block
penggunaan MPI_Allreduce
, yang melakukan lebih banyak komunikasi MPI_Reduce
dan MPI_Scatter
gabungan, sebenarnya sedikit lebih cepat. Ini adalah sesuatu yang baru-baru ini saya temukan dan merupakan pelanggaran yang menarik dari prinsip konsistensi diri kinerja dalam MPI (prinsip ini dijelaskan secara lebih rinci dalam "Pedoman Kinerja MPI yang Konsisten Sendiri" ).
Dalam kasus spesifik pencar + kumpulkan versus allgather, pertimbangkan bahwa pada yang pertama, semua data harus pergi ke dan dari satu proses tunggal, yang membuatnya menjadi hambatan, sedangkan pada allgather, data dapat mengalir masuk dan keluar dari semua peringkat segera , karena semua peringkat memiliki beberapa data untuk dikirim ke semua peringkat lainnya. Namun, mengirim data dari semua node sekaligus tidak selalu merupakan ide yang baik pada beberapa jaringan.
Akhirnya, cara terbaik untuk menjawab pertanyaan ini adalah dengan melakukan yang berikut dalam kode Anda dan menjawab pertanyaan dengan eksperimen.
#ifdef TWO_MPI_CALLS_ARE_BETTER_THAN_ONE
MPI_Scatter(..)
MPI_Gather(..)
#else
MPI_Allgather(..)
#endif
Opsi yang lebih baik lagi adalah membuat kode Anda mengukurnya secara eksperimental selama dua iterasi pertama, kemudian gunakan mana yang lebih cepat untuk iterasi yang tersisa:
const int use_allgather = 1;
const int use_scatter_then_gather = 2;
int algorithm = 0;
double t0 = 0.0, t1 = 0.0, dt1 = 0.0, dt2 = 0.0;
while (..)
{
if ( (iteration==0 && algorithm==0) || algorithm==use_scatter_then_gather )
{
t0 = MPI_Wtime();
MPI_Scatter(..);
MPI_Gather(..);
t1 = MPI_Wtime();
dt1 = t1-t0;
}
else if ( (iteration==1 && algorithm==0) || algorithm==use_allgather)
{
t0 = MPI_Wtime();
MPI_Allgather(..);
t1 = MPI_Wtime();
dt2 = t1-t0;
}
if (iteration==1)
{
dt2<dt1 ? algorithm=use_allgather : algorithm=use_scatter_then_gather;
}
}
MPI_Scatter
diikuti olehMPI_Gather
tidak menyediakan komunikasi yang sama semantik sebagaiMPI_Allgather
. Mungkin ada redundansi yang terlibat saat Anda mengekspresikan operasi dengan cara baik?