2015-08-31 17 views
6

बहुत गुगल करने के बाद, मुझे नहीं पता कि इस समस्या का कारण क्या है। यहां यह है:MPI_Allgather में विचित्र डेडलॉक

मेरे पास मेरे कोड में MPI_Allgather के लिए एक साधारण कॉल है, जिसमें मेरे पास डबल, ट्रिपल और चौगुनी-जांच सही है (भेजें/प्राप्त करें बफर सही ढंग से आकार में हैं; कॉल में भेजें/प्राप्त आकार हैं सही), लेकिन प्रक्रियाओं की 'बड़ी' संख्याओं के लिए मुझे या तो डेडलॉक या MPI_ERR_TRUNCATE मिलता है। एमपीजी_COM_split का उपयोग कर ऑलगैदर के लिए इस्तेमाल होने वाले संवाददाता को MPI_COMM_WORLD से विभाजित किया गया है। मेरे वर्तमान परीक्षण के लिए, रैंक 0 एक संवाददाता के पास जाता है, और शेष रैंक दूसरे संवाददाता के पास जाते हैं। 6 कुल रैंक या उससे कम के लिए, ऑलगदर ठीक काम करता है। अगर मैं 7 रैंक का उपयोग करता हूं, तो मुझे एक एमपीआई_ईआरआर_TRUNCATE मिलता है। 8 रैंक, डेडलॉक। मैंने सत्यापित किया है कि संवाददाताओं को सही ढंग से विभाजित किया गया था (MPI_Comm_rank और MPI_Comm_size दोनों कॉमम्स के लिए सभी रैंकों पर सही है)।

मैंने मैन्युअल रूप से प्रत्येक प्रेषण का आकार सत्यापित किया है और बफर प्राप्त किया है, और अधिकतम प्राप्तकर्ताओं को प्राप्त किया है। मेरा पहला कामकाज MPI_Aggather को प्रत्येक प्रक्रिया में एमपीआई_गैदर के फॉर-लूप के लिए स्वैप करना था। यह उस मामले के लिए काम करता था, लेकिन मेरे कोड (एमईटीआईएस का उपयोग करके विभाजित सीएफडी ग्रिड) को दिए गए मेष को बदलकर समस्या को वापस लाया। अब मेरा समाधान, जिसे मैं तोड़ने में सक्षम नहीं हूं, अभी तक ऑलगदर को ऑलगदरव के साथ प्रतिस्थापित करना है, जो मुझे लगता है कि वैसे भी अधिक कुशल है क्योंकि मेरे पास डेटा के विभिन्न प्रकार के टुकड़े भेजे जा रहे हैं प्रत्येक प्रक्रिया।

संदर्भ में प्रासंगिक अपमान कोड (मुझे उम्मीद है) यहां है; अगर मुझे कुछ याद आया है, तो प्रश्न में ऑल्गदर this file की लाइन 59 9 पर है।

// 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); 

मैं वर्तमान में openmpi 1.6.4, जी ++ 4.9.2, और एक AMD FX-8350 8 कोर रैम 16GB के साथ प्रोसेसर उपयोग कर रहा हूँ, प्राथमिक ओएस फ्रेया 0.3 की नवीनतम अद्यतन चल रहा है (मूल रूप से Ubuntu 14.04) । हालांकि, मुझे CentOS, Intel हार्डवेयर, और MPICH2 का उपयोग करके किसी अन्य मशीन पर यह समस्या भी मिली है।

कोई विचार? मैंने सुना है कि समान मुद्दों को ठीक करने के लिए एमपीआई के आंतरिक बफर आकार को बदलना संभव हो सकता है, लेकिन ऐसा करने की त्वरित कोशिश (जैसा कि http://www.caps.ou.edu/pipermail/arpssupport/2002-May/000361.html में दिखाया गया है) का कोई प्रभाव नहीं पड़ा।

संदर्भ के लिए, यह समस्या यहां दिखाए गए एक जैसा ही है: https://software.intel.com/en-us/forums/topic/285074, सिवाय इसके कि मेरे मामले में, मेरे पास एक ही डेस्कटॉप कंप्यूटर पर 8 कोर के साथ केवल 1 प्रोसेसर है। पर निम्न उत्पादन के साथ

mpicxx -std=c++11 mpiTest.cpp -o mpitest 
mpirun -np 8 ./mpitest 

:

#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; 
} 

ऊपर कोड संकलित किया गया था और के रूप में चलाने:

अद्यतन मैं एक साथ इस असफलता का एक minimalist उदाहरण डाल करने के लिए प्रबंधित किया है मेरे 16-कोर सेंटोस और मेरी 8-कोर उबंटू मशीनें:

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 

ध्यान दें कि प्रत्येक संवाददाता से केवल 2 रैंक ऑलगदर से बाहर निकलें; यह मेरे वास्तविक कोड में नहीं होता है ('टूटा' संचारक पर कोई रैंक ऑलगदर से बाहर नहीं निकलता है), लेकिन अंतिम परिणाम वही है - जब तक मैं इसे मार नहीं जाता तब तक कोड लटकता है।

मुझे लगता है कि इस प्रक्रिया में प्रत्येक प्रक्रिया पर अलग-अलग संख्याओं के साथ कुछ करने के लिए कुछ है, लेकिन जहां तक ​​मैं एमपीआई दस्तावेज और ट्यूटोरियल से कह सकता हूं, यह माना जाना चाहिए, सही?बेशक, MPI_Allgatherv थोड़ा अधिक लागू है, लेकिन सादगी के कारणों के लिए मैं इसके बजाय ऑल्गदर का उपयोग कर रहा हूं।

+2

आपका दूसरा कोड स्निपेट आपके विवरण के अनुरूप नहीं है। आपके द्वारा चलाए जा रहे वास्तविक कोड को पोस्ट करने के बारे में कैसे? और एमसीवीई बनाने की कोशिश करें। – Jeff

+0

मैंने कोड स्निपेट अपडेट किया है और पूर्ण (2000+ लाइन) फ़ाइल के लिए एक लिंक प्रदान किया है; मेरे मूल एमपीआई_गैदर वर्कअराउंड ने काम करना बंद कर दिया ताकि मैंने उस स्निपेट को हटा दिया। मुझे एक साधारण कार्यक्रम में प्रभावों को डुप्लिकेट करना पड़ सकता है जो प्रत्येक रैंक पर एक यादृच्छिक आकार के वेक्टर (अधिकतम 10,000 int तक) आवंटित करता है और उपरोक्त MPI_Allgather करता है, लेकिन मुझे निश्चित नहीं है और मैं शायद नहीं आज इसे वापस पाने में सक्षम। मुझे मौका मिलने पर मैं इसे पोस्ट करूंगा। – Jacob

+2

यदि आप diff procs पर रैंड का उपयोग करते हैं, तो तर्क मेल नहीं खाते। यह एमपीआई का अवैध उपयोग है। जड़ और बकाया पर लगातार रैंड कॉल करें। – Jeff

उत्तर

4

यदि आपको इनपुट प्रक्रियाएं सभी प्रक्रियाओं में समान नहीं हैं तो आपको MPI_Allgatherv का उपयोग करना होगा।

सटीक होने के लिए, टाइप हस्ताक्षर count,type का मिलान करना चाहिए, क्योंकि तकनीकी रूप से आप अलग-अलग डेटाटाइप (जैसे एन तत्व बनाम 1 तत्व जो एन तत्वों का एक समान प्रकार है) के साथ समान मौलिक प्रतिनिधित्व प्राप्त कर सकते हैं, लेकिन यदि आप हर जगह एक ही तर्क का प्रयोग करें, जो एमपीआई सामूहिक सामूहिक उपयोग है, तो आपकी गणना हर जगह मेल खाना चाहिए।

नवीनतम एमपीआई मानक के संबंधित भाग (3.1) पेज 165 पर है:

प्रकार एक प्रक्रिया पर, sendcount, sendtype के साथ जुड़े recvcount के साथ जुड़े प्रकार हस्ताक्षर के बराबर होना चाहिए हस्ताक्षर, किसी भी अन्य प्रक्रिया पर recvtype।

संबंधित मुद्दे