2015-08-31 36 views
6

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ế.

+2

Đ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

+0

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

+2

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

Trả lời

4

Bạn phải sử dụng MPI_Allgatherv nếu số lượng đầu vào không giống nhau trên tất cả các quy trình.

Để chính xác, những gì phải khớp là chữ ký loại count,type, vì về mặt kỹ thuật, bạn có thể biểu diễn cùng với các kiểu dữ liệu khác nhau (ví dụ: phần tử N so với phần tử 1 là một loại phần tử liền kề), nhưng nếu bạn sử dụng cùng một đối số ở khắp mọi nơi, đó là cách sử dụng phổ biến của tập thể MPI, khi đó số lượng của bạn phải phù hợp với mọi nơi.

Phần liên quan của các tiêu chuẩn MPI mới nhất (3.1) là trên trang 165:

Các loại chữ ký liên quan đến sendcount, sendtype, tại một quá trình phải bằng loại chữ ký liên quan đến recvcount, recvtype tại bất kỳ quy trình nào khác.