Sau nhiều Googling, tôi không biết nguyên nhân gây ra sự cố này. Đây là:Bế tắc bế tắc trong MPI_Allgather
Tôi có một cuộc gọi đơn giản tới MPI_Allgather trong mã của tôi mà tôi đã kiểm tra gấp đôi, gấp ba lần và gấp bốn lần đúng (bộ đệm gửi/nhận có kích thước phù hợp; kích thước gửi/nhận trong cuộc gọi là chính xác), nhưng đối với số lượng lớn các quy trình tôi nhận được bế tắc hoặc MPI_ERR_TRUNCATE. Bộ giao tiếp được sử dụng cho Allgather được tách ra từ MPI_COMM_WORLD bằng MPI_Comm_split. Đối với thử nghiệm hiện tại của tôi, thứ hạng 0 đi tới một người giao tiếp, và các cấp bậc còn lại đi tới một người giao tiếp thứ hai. Đối với tổng số 6 cấp bậc hoặc ít hơn, Allgather hoạt động tốt. Nếu tôi sử dụng 7 cấp bậc, tôi nhận được một MPI_ERR_TRUNCATE. 8 bậc, bế tắc. Tôi đã xác minh rằng các nhà giao tiếp đã được chia một cách chính xác (MPI_Comm_rank và MPI_Comm_size là chính xác trên tất cả các cấp bậc cho cả hai Comms).
Tôi đã xác minh thủ công kích thước của mỗi bộ đệm gửi và nhận và số lượng nhận tối đa. Cách giải quyết đầu tiên của tôi là trao đổi MPI_Allgather cho một vòng lặp của MPI_Gather cho mỗi tiến trình. Điều này đã làm việc cho một trường hợp đó, nhưng việc thay đổi các mắt lưới được cung cấp cho mã của tôi (các lưới CFD được phân vùng bằng cách sử dụng METIS) đã đưa vấn đề trở lại. Bây giờ giải pháp của tôi, mà tôi chưa thể phá vỡ (chưa), là thay thế Allgather bằng Allgatherv, mà tôi cho là hiệu quả hơn vì tôi có số lượng dữ liệu khác nhau được gửi từ mỗi quá trình.
Đây là (tôi hy vọng) mã vi phạm có liên quan trong ngữ cảnh; nếu tôi đã bỏ lỡ điều gì đó, Allgather được đề cập là trên dòng 599 của this file.
// Get the number of mpiFaces on each processor (for later communication)
// 'nProgGrid' is the size of the communicator 'gridComm'
vector<int> nMpiFaces_proc(nProcGrid);
// This MPI_Allgather works just fine, every time
// int nMpiFaces is assigned on preceding lines
MPI_Allgather(&nMpiFaces,1,MPI_INT,nMpiFaces_proc.data(),1,MPI_INT,gridComm);
int maxNodesPerFace = (nDims==2) ? 2 : 4;
int maxNMpiFaces = getMax(nMpiFaces_proc);
// The matrix class is just a fancy wrapper around std::vector that
// allows for (i,j) indexing. The getSize() and getData() methods just
// call the size() and data() methods, respectively, of the underlying
// vector<int> object.
matrix<int> mpiFaceNodes_proc(nProcGrid,maxNMpiFaces*maxNodesPerFace);
// This is the MPI_Allgather which (sometimes) doesn't work.
// vector<int> mpiFaceNodes is assigned in preceding lines
MPI_Allgather(mpiFaceNodes.data(),mpiFaceNodes.size(),MPI_INT,
mpiFaceNodes_proc.getData(),maxNMpiFaces*maxNodesPerFace,
MPI_INT,gridComm);
Tôi hiện đang sử dụng OpenMPI 1.6.4, g ++ 4.9.2, và FX-8350 vi xử lý 8-core AMD với 16GB RAM, chạy các bản cập nhật mới nhất của Tiểu OS Freya 0.3 (về cơ bản Ubuntu 14.04) . Tuy nhiên, tôi cũng đã có vấn đề này trên máy khác sử dụng CentOS, phần cứng Intel và MPICH2.
Bất kỳ ý tưởng nào? Tôi đã nghe nói rằng có thể thay đổi (các) kích thước bộ đệm nội bộ của MPI để khắc phục các vấn đề tương tự, nhưng một cách nhanh chóng để làm như vậy (như được hiển thị trong http://www.caps.ou.edu/pipermail/arpssupport/2002-May/000361.html) không có hiệu lực.
Để tham khảo, vấn đề này rất giống với sự cố ở đây: https://software.intel.com/en-us/forums/topic/285074, ngoại trừ trường hợp của tôi, tôi chỉ có 1 bộ xử lý với 8 lõi, trên một máy tính để bàn.
CẬP NHẬT tôi đã quản lý để đặt lại với nhau một ví dụ nhỏ gọn của thất bại này:
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
#include "mpi.h"
using namespace std;
int main(int argc, char* argv[])
{
MPI_Init(&argc,&argv);
int rank, nproc, newID, newRank, newSize;
MPI_Comm newComm;
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&nproc);
newID = rank%2;
MPI_Comm_split(MPI_COMM_WORLD,newID,rank,&newComm);
MPI_Comm_rank(newComm,&newRank);
MPI_Comm_size(newComm,&newSize);
srand(time(NULL));
// Get a different 'random' number for each rank on newComm
//int nSend = rand()%10000;
//for (int i=0; i<newRank; i++) nSend = rand()%10000;
/*! -- Found a set of #'s which fail for nproc=8: -- */
int badSizes[4] = {2695,7045,4256,8745};
int nSend = badSizes[newRank];
cout << "Comm " << newID << ", rank " << newRank << ": nSend = " << nSend << endl;
vector<int> send(nSend);
for (int i=0; i<nSend; i++)
send[i] = rand();
vector<int> nRecv(newSize);
MPI_Allgather(&nSend,1,MPI_INT,nRecv.data(),1,MPI_INT,newComm);
int maxNRecv = 0;
for (int i=0; i<newSize; i++)
maxNRecv = max(maxNRecv,nRecv[i]);
vector<int> recv(newSize*maxNRecv);
MPI_Barrier(MPI_COMM_WORLD);
cout << "rank " << rank << ": Allgather-ing data for communicator " << newID << endl;
MPI_Allgather(send.data(),nSend,MPI_INT,recv.data(),maxNRecv,MPI_INT,newComm);
cout << "rank " << rank << ": Done Allgathering-data for communicator " << newID << endl;
MPI_Finalize();
return 0;
}
Đoạn mã trên đã được biên soạn và chạy như:
mpicxx -std=c++11 mpiTest.cpp -o mpitest
mpirun -np 8 ./mpitest
với sản lượng sau trên cả CentOS 16 lõi và các máy Ubuntu 8 lõi của tôi:
Comm 0, rank 0: nSend = 2695
Comm 1, rank 0: nSend = 2695
Comm 0, rank 1: nSend = 7045
Comm 1, rank 1: nSend = 7045
Comm 0, rank 2: nSend = 4256
Comm 1, rank 2: nSend = 4256
Comm 0, rank 3: nSend = 8745
Comm 1, rank 3: nSend = 8745
rank 5: Allgather-ing data for communicator 1
rank 6: Allgather-ing data for communicator 0
rank 7: Allgather-ing data for communicator 1
rank 0: Allgather-ing data for communicator 0
rank 1: Allgather-ing data for communicator 1
rank 2: Allgather-ing data for communicator 0
rank 3: Allgather-ing data for communicator 1
rank 4: Allgather-ing data for communicator 0
rank 5: Done Allgathering-data for communicator 1
rank 3: Done Allgathering-data for communicator 1
rank 4: Done Allgathering-data for communicator 0
rank 2: Done Allgathering-data for communicator 0
Lưu ý rằng chỉ có 2 trong số các cấp bậc từ mỗi người giao tiếp thoát khỏi Allgather; đây không phải là những gì xảy ra trong mã thực tế của tôi (không có thứ hạng trên giao tiếp 'hỏng' thoát Allgather), nhưng kết quả cuối cùng là như nhau - mã treo cho đến khi tôi giết nó.
Tôi đoán điều này có liên quan đến số lượng gửi khác nhau trên mỗi quy trình, nhưng theo như tôi có thể nói từ tài liệu và hướng dẫn của MPI tôi đã thấy, điều này được cho là được phép, đúng không?Tất nhiên, MPI_Allgatherv là một chút áp dụng hơn, nhưng vì lý do đơn giản tôi đã sử dụng Allgather thay thế.
Đoạn mã thứ hai của bạn không nhất quán với mô tả của bạn. Làm cách nào để đăng mã thực tế bạn đang chạy? Và cố gắng tạo MCVE. – Jeff
Tôi đã cập nhật đoạn mã và cung cấp liên kết đến tệp (2000 dòng) đầy đủ; bản sửa lỗi MPI_Gather ban đầu của tôi đã ngừng hoạt động nên tôi đã xóa đoạn mã đó. Tôi có thể đã có một số may mắn sao chép các hiệu ứng trong một chương trình đơn giản phân bổ một vector có kích thước ngẫu nhiên (tối đa 10.000 int) trên mỗi cấp bậc và thực hiện MPI_Allgather ở trên, nhưng tôi không chắc chắn và có lẽ tôi sẽ không có thể quay lại với nó ngay hôm nay. Tôi sẽ đăng nó khi tôi có cơ hội. – Jacob
Nếu bạn sử dụng rand trên procs khác, args sẽ không khớp. Đây là việc sử dụng MPI không hợp lệ. Gọi rand trên root và bcast để nhất quán. – Jeff