2011-03-20 17 views
6

कह सकती है कि 2 प्रक्रियाएं भाग ले रही हैं। प्रक्रिया 0 (रैंक 0)प्रोसेसर से MPI_Gatherv कॉलम कैसे करें, जहां प्रत्येक प्रक्रिया कॉलम की विभिन्न संख्या

A = { a d 
     b e 
     c f 
    } 

और इस प्रक्रिया 1 (रैंक 1)

A = { g 
     h 
     i 
    } 

है मैं दोनों प्रोसेसर चाहते 0 रैंक करने के लिए इन स्तंभों भेजने के लिए इतना है कि रैंक 0 में निम्नलिखित होगा शामिल किए जाएं एक और 2 डी-सरणी।

B = { a d g 
     b e h 
     c f i 
    } 

मैं MPI_Gatherv के लिए एक नया कॉलम डेटा प्रकार बना रहा हूं और निम्न कोड को आजमा रहा हूं, जो मुझे कहीं नहीं मिल रहा है।

मेरे विशिष्ट प्रश्न हैं:

  1. मैं इस
  2. क्या send_type और recv_type होना चाहिए कैसे संपर्क करना चाहिए।
  3. विस्थापन कैसे निर्दिष्ट किया जाना चाहिए

धन्यवाद (वे नए डेटा प्रकार या MPI_CHAR की अवधि में होना चाहिए)।

यह मेरा कोड है:

#include <stdio.h> 
#include <mpi.h> 

int main(int argc, char *argv[]) 
{ 
    int numprocs, my_rank; 
    long int i, j; 
    MPI_Status status; 
    char **A; 
    char **B; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); 

    if(my_rank == 0) 
    { 
    A = (char **)calloc((3), sizeof(char *)); 
    B = (char **)calloc((3), sizeof(char *)); 
    for(i=0; i<3; ++i) 
    { 
     A[i] = (char *)calloc(2, sizeof(char)); 
     B[i] = (char *)calloc(3, sizeof(char)); 
    } 

    A[0][0] = 'a'; 
    A[1][0] = 'b'; 
    A[2][0] = 'c'; 
    A[0][1] = 'd'; 
    A[1][1] = 'e'; 
    A[2][1] = 'f'; 
    } 
    else 
    { 
    A = (char **)calloc((3), sizeof(char *)); 
    for(i=0; i<3; ++i) 
    { 
     A[i] = (char *)calloc(1, sizeof(char)); 
    } 
    A[0][0] = 'g'; 
    A[1][0] = 'h'; 
    A[2][0] = 'i'; 

    } 
    MPI_Datatype b_col_type; 
    MPI_Type_vector(3, 1, 1, MPI_CHAR, &b_col_type); 
    MPI_Type_commit(&b_col_type); 
    int displs[2] = {0, 2}; 
    int recvcounts[2] = {2, 1}; 
    MPI_Gatherv(&A[0][0], recvcounts[my_rank], b_col_type, &B[0][0], recvcounts, displs, b_col_type, 0, MPI_COMM_WORLD); 
    if(my_rank == 0) 
    { 
    for(i=0; i<3; ++i) 
    { 
     for(j=0; j<3; ++j) 
     printf("%c ", B[i][j]); 
     printf("\n"); 
    } 
    } 
    MPI_Finalize(); 
    return 0; 
} 
+0

आपका क्या मतलब है "यह आपको कहीं नहीं मिल रहा है"? सही समस्या क्या है? – suszterpatt

+0

तो अगर मैं ऊपर कोड सामान कि बी करने के लिए हो जाता है चलाने का प्रयास केवल $ mpirun -np 2 try_gather एक घ तो केवल रैंक 0 अपने 2 तत्वों को भेजने में सक्षम है। मैंने displs और recvcounts के मूल्यों के साथ tweaking करने की कोशिश की, हालांकि मैं जो लक्ष्य मैं लक्ष्य कर रहा हूं वह प्राप्त नहीं कर सका। वर्तमान कोड कम से कम 2 अक्षर सही जगह पर डाल दिया। मैं टिप्पणी अनुभाग में कोड को प्रारूपित करने का प्रयास करने पर छोड़ देता हूं। मूल रूप से 'ए' और 'डी' सही जगह पर जाते हैं। शेष सभी सरणी बी – Reep

उत्तर

6

तो सबसे पहले बंद - और इस एमपीआई और सी सरणियों के साथ हर समय आता है - क्या तुम सच में मानक सी दो आयामी सरणी बात नहीं कर सकते हैं। चलो इस पर नजर डालते हैं:

A = (char **)calloc((3), sizeof(char *)); 
for(i=0; i<3; ++i) 
{ 
    A[i] = (char *)calloc(2, sizeof(char)); 
} 

यह निश्चित रूप से पात्रों में से एक 3x2 सरणी आवंटित करेगा, लेकिन आप पता नहीं कैसे परिणामी डेटा स्मृति में खर्च की गई थी की है। विशेष रूप से, पर सभी पर कोई गारंटी नहीं है कि A[1][0] तुरंत A[0][1] का पालन करता है। इससे एमपीआई डेटाटाइप बनाने में बहुत मुश्किल हो जाती है जो डेटा संरचना का विस्तार करती है! आप इसे में 3x2 सन्निहित बाइट्स आवंटित, और फिर बनाने के लिए सरणी बिंदु की जरूरत है:

char **charalloc2d(int n, int m) { 
    char *data = (char *)calloc(n*m,sizeof(char)); 
    char **array = (char **)calloc(n, sizeof(char *)); 
    for (int i=0; i<n; i++) 
     array[i] = &(data[i*m]); 

    return array; 
} 

void charfree2d(char **array) { 
    free(array[0]); 
    free(array); 
    return; 
} 

/* ... */ 
nrows = 3; 
ncols = 2; 
A = charalloc2d(nrows,ncols); 

अब हम सरणी के लेआउट के बारे में कुछ पता है, और उस पर निर्भर डेटाटाइप्स निर्माण करने के लिए कर सकते हैं।

आप डेटा प्रकार के साथ सही रास्ते पर हैं -

MPI_Datatype b_col_type; 
MPI_Type_vector(3, 1, 1, MPI_CHAR, &b_col_type); 
MPI_Type_commit(&b_col_type); 

MPI_Type_vector के हस्ताक्षर (गिनती, blocklen, कदम, OLD_TYPE, * newtype) है।
हम nrows अक्षर चाहते हैं, जो 1 के ब्लॉक में आते हैं; लेकिन वे अलग ncols दूरी हैं; तो वह रास्ता है।

ध्यान दें कि B की बजाय यह वास्तव में A सरणी का कॉलम प्रकार है; प्रकार सरणी में कॉलम की संख्या पर निर्भर करेगा। इसलिए प्रत्येक प्रक्रिया एक अलग प्रेषण का उपयोग कर रही है, जो ठीक है।

MPI_Datatype a_col_type; 
MPI_Type_vector(nrows, 1, ncols, MPI_CHAR, &a_col_type); 
MPI_Type_commit(&a_col_type); 

अंतिम चरण MPI_Gatherv है, और यहाँ आप एक छोटे से प्यारा रहना होगा। चाल यह है कि, हम एक समय में इन चीजों में से कई को भेजना और प्राप्त करना चाहते हैं - यानी, कई लगातार।लेकिन हमें अगली कॉलम की जरूरत है कि नारो * नकोल्स दूर हो जाएं, लेकिन सिर्फ एक चार दूर। सौभाग्य से, हम डेटा संरचना के ऊपरी बाउंड को निचले बाउंड से केवल एक वर्ण दूर रखने के लिए ऐसा कर सकते हैं, ताकि अगला तत्व सही जगह पर शुरू हो सके। यह the standard द्वारा अनुमत है, और वास्तव में धारा 4.1.4 में उनके उदाहरणों में से एक इस पर निर्भर करता है।

कि ऐसा करने के लिए, हम एक आकृति परिवर्तन प्रकार है कि सिर्फ एक बाइट समाप्त होने के बाद यह शुरू होता है बनाने के लिए:

MPI_Type_create_resized(a_col_type, 0, 1*sizeof(char), &new_a_col_type); 
MPI_Type_commit(&new_a_col_type); 

और इसी तरह B के लिए; और अब हम इनमें से गुणकों को भेज और प्राप्त कर सकते हैं क्योंकि एक उम्मीद करेगा। तो मेरे लिए निम्नलिखित काम करता है:

#include <stdio.h> 
#include <stdlib.h> 
#include <mpi.h> 

char **charalloc2d(int n, int m) { 
    char *data = (char *)calloc(n*m,sizeof(char)); 
    char **array = (char **)calloc(n, sizeof(char *)); 
    for (int i=0; i<n; i++) 
     array[i] = &(data[i*m]); 

    return array; 
} 

void charfree2d(char **array) { 
    free(array[0]); 
    free(array); 
    return; 
} 


int main(int argc, char *argv[]) 
{ 
    int numprocs, my_rank; 
    int nrows, ncols, totncols; 
    long int i, j; 
    char **A; 
    char **B; 
    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs); 
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); 

    if(my_rank == 0) 
    { 
     nrows=3; 
     ncols=2; 
     totncols = 3; 

     A = charalloc2d(nrows, ncols); 
     B = charalloc2d(nrows, totncols); 

     A[0][0] = 'a'; 
     A[1][0] = 'b'; 
     A[2][0] = 'c'; 
     A[0][1] = 'd'; 
     A[1][1] = 'e'; 
     A[2][1] = 'f'; 
    } 
    else 
    { 
     nrows = 3; 
     ncols = 1; 
     A = charalloc2d(nrows, ncols); 
     B = charalloc2d(1,1); /* just so gatherv survives */ 
     A[0][0] = 'g'; 
     A[1][0] = 'h'; 
     A[2][0] = 'i'; 

    } 
    MPI_Datatype a_col_type, new_a_col_type; 
    MPI_Type_vector(nrows, 1, ncols, MPI_CHAR, &a_col_type); 
    MPI_Type_commit(&a_col_type); 

    /* make the type have extent 1 character -- now the next 
    * column starts in the next character of the array 
    */ 
    MPI_Type_create_resized(a_col_type, 0, 1*sizeof(char), &new_a_col_type); 
    MPI_Type_commit(&new_a_col_type); 

    MPI_Datatype b_col_type, new_b_col_type; 
    if (my_rank == 0) { 
     MPI_Type_vector(nrows, 1, totncols, MPI_CHAR, &b_col_type); 
     MPI_Type_commit(&b_col_type); 

     /* similarly "resize" b columns */ 
     MPI_Type_create_resized(b_col_type, 0, 1*sizeof(char), &new_b_col_type); 
     MPI_Type_commit(&new_b_col_type); 
    } 

    int displs[2] = {0, 2}; 
    int recvcounts[2] = {2, 1}; 
    MPI_Gatherv(A[0], recvcounts[my_rank], new_a_col_type, 
       B[0], recvcounts, displs, new_b_col_type, 
       0, MPI_COMM_WORLD); 
    if(my_rank == 0) 
    { 
     for(i=0; i<3; ++i) 
     { 
      for(j=0; j<3; ++j) 
       printf("%c ", B[i][j]); 
      printf("\n"); 
     } 
    } 
    MPI_Finalize(); 
    return 0; 
} 
+0

धन्यवाद जॉन में हैं। मुझे बाद में एहसास हुआ कि मेरे सरणी स्मृति में संगत नहीं थे। इसलिए अब मैं प्रत्येक प्रक्रिया के लिए अलग MPI_Datatype के साथ एक भेजें/रिकिव संयोजन का उपयोग करने की योजना बना रहा हूं और MPI_Gatherv का उपयोग नहीं करता हूं। मुझे लगता है कि आप भी यही कह रहे हैं? – Reep

+0

कॉलम-प्रमुख क्रम पर मैट्रिक्स स्टोर करें। इस तरह, एक कॉलम एक साधारण 'एमपीआई_Contiguous' डेटाटाइप होगा, और आप आसानी से' Gatherv() '(विस्थापन 0 के साथ प्रक्रिया 0 से 2 कॉलम, और विस्थापन 2 के साथ प्रक्रिया 1 से 1 कॉलम) के साथ उन्हें आसानी से भेज/प्राप्त कर सकते हैं। यह वैसे भी फिट बैठता है जिस तरह से आप अपने डेटा को बेहतर तरीके से विघटित करते हैं। – suszterpatt

+0

@suszterpatt मैं कॉलम प्रमुख प्रारूप में स्टोर नहीं करना चाहता क्योंकि विभिन्न प्रोसेसर पंक्ति के बड़े क्रम में उनके 'ए [] []' सरणी में डेटा की गणना और संग्रह करते हैं और वास्तविकता में सरणी काफी बड़ी हैं, इसलिए लिखने से संभवतः लिखा जाएगा बहुत मेमोरी थ्रैशिंग। – Reep

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