2017-10-25 6 views
0

MPI를 처음 접했고 이것이 올바른 접근 방법인지 확신 할 수 없습니다. 또는이 방식으로 MPI를 사용해야하지만 내 문제는 다음과 같습니다.구조체 배열의 각 요소에 대한 mpi 통신기

사용자 정의 구조에 대한 포인터 배열이 있습니다. 각 프로세스에서 어떤 일이 일어나고 있는지에 따라 배열 요소는 NULL이거나 사용자 정의 구조의 인스턴스에 대한 포인터 일 수 있습니다. 이제 MPI를 통해 서로 통신하기 위해 배열의 요소가 필요합니다. 일부는 존재하지 않기 때문에 이것은 문제가됩니다.

나는 정교해야한다 : 구조는 통신이 일어날 필요가있는 기능에 대한 포인터를 가지고있다. 요소가 있으면 함수가 호출됩니다. 그렇지 않은 경우.

내 아이디어 : 요소가 NOT NULL 인 모든 프로세서를 포함하는 배열의 각 요소에 전용 MPI 통신기를 만듭니다. 그런 다음 해당 요소에 대한 통신 중에이 통신기를 참조하십시오.

배열의 각 요소에 대해 하나씩 MPI 통신기의 "배열"을 만들 수 있습니까? 그리고 나서 각 요소에 대해 MPI_COMM_ARRAY [i]를 참조 하시겠습니까? 아니면 완전히 막 다른 길에 있고 배열 엔트리로서 NULL을 사용하면 안된다. 이것을 "깔끔하게"코딩하는 방법은 무엇입니까?

이것은 내가 지금 가지고있는 것의 단순화입니다. 우연히 모든 프로세스에서 셀이 존재하면 작동합니다. 그렇지 않으면 실패합니다. 예제 코드 :

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


void * createcell(); 
void Cell_givenumberofvertices(void * _self, int * NbOfVertices); 
void Cell_givenumberofvertices_parallel(void * _self, int * NbOfVertices); 
void Cell_addvertex(void * _self); 
void addvertex(void * _self); 
void getnumberofvertices(void * _self, int * NbOfVertices); 


struct Cell{ 
    unsigned NbOfVertices; 
    void (* givenumberofvertices)(void * _self, int * NbOfVertices); 
    void (* addvertex)(void * _self); 
}; 

void * createcell(){ 
    struct Cell * self = calloc(1, sizeof(struct Cell)); 
    int world_size; 

    MPI_Comm_size(MPI_COMM_WORLD,&world_size); 

    self->NbOfVertices = 0; 
    self->addvertex = Cell_addvertex; 

    if(world_size==0) self->givenumberofvertices = Cell_givenumberofvertices; 
    else self->givenumberofvertices = Cell_givenumberofvertices_parallel; 

    return self; 
} 

void Cell_givenumberofvertices(void * _self, int * NbOfVertices){ 
    struct Cell * self = _self; 
    * NbOfVertices = self->NbOfVertices; 
    return; 
} 

void Cell_givenumberofvertices_parallel(void * _self, int * NbOfVertices){ 
    struct Cell * self = _self; 
    int world_size, world_rank; 
    int i; 
    int * NbVertxOnProcess; 
    int totalnumberofvertices=0; 

    MPI_Comm_size(MPI_COMM_WORLD,&world_size); 
    MPI_Comm_rank(MPI_COMM_WORLD,&world_rank); 
    NbVertxOnProcess = (int *) malloc(world_size*sizeof(int)); 

    MPI_Gather(&(self->NbOfVertices),1,MPI_UNSIGNED,NbVertxOnProcess,1,MPI_INT,0,MPI_COMM_WORLD); 

    for(i=0;i<world_size;i++) totalnumberofvertices+=NbVertxOnProcess[i]; 

    * NbOfVertices = totalnumberofvertices; 
    return; 
} 

void Cell_addvertex(void * _self){ 
    struct Cell * self = _self; 
    self->NbOfVertices ++; 
    return; 
} 

void addvertex(void * _self){ 
    struct Cell * self = _self; 
    self->addvertex(self); 
} 

void getnumberofvertices(void * _self, int * NbOfVertices){ 
    struct Cell * self = _self; 
    self->givenumberofvertices(self, NbOfVertices); 
} 



int main(int argc, char *argv[]) { 
    void ** cells; 
    int i,j; 
    const int numberofcells = 100; 
    const int numberofvertices = 100; 
    const float domainlength = 115.4; 
    float grid[numberofcells]; 
    float vertexcoordinates[numberofvertices]; 
    int world_rank; 

    MPI_Init(NULL,NULL); 

    /* create array of Cell pointers */ 
    cells = (void **) calloc(numberofcells,sizeof(void *)); 

    /* create grid */ 
    for(i=0;i<numberofcells;i++){ 
    grid[i]=domainlength/numberofcells*(i+1); 
    } 
    /* generate random vertex coordinates */ 
    MPI_Comm_rank(MPI_COMM_WORLD,&world_rank); 
    srand((unsigned int) world_rank); 
    for(i=0;i<numberofvertices;i++){ 
    vertexcoordinates[i]=((float)rand()/(float)(RAND_MAX)) * domainlength; 
    } 
    /* find the cell the vertex is in */ 
    for(i=0;i<numberofvertices;i++){ 
    for(j=0;j<numberofcells;j++){ 
     float lb, ub; 
     if(j==0) lb=0.0; 
     else lb=grid[j-1]; 
     ub = grid[j]; 
     if(lb<vertexcoordinates[i]&&vertexcoordinates[i]<ub){ 
     if(!cells[j]){ 
      cells[j]=createcell(); 
     } 
     addvertex(cells[j]); 
     } 
    } 
    } 

    for(i=0;i<numberofcells;i++){ 
    if(cells[i]){ 
     int NbVertxInCell; 
     getnumberofvertices(cells[i], &NbVertxInCell); 
     printf("%i vertices in cell number %i \n",NbVertxInCell,i); 
    } 
    } 
    MPI_Finalize(); 
    return 0; 
} 
+1

몇 가지 코드를 제시해주십시오 수 있습니다 될 수있다, 당신의 설명은 따라하기가 매우 어렵다.예를 들어 "사용자 정의 구조체 배열"은 사용자 정의 구조체에 대한 배열로 간주됩니다. –

+0

충분히 공정하게, 나는 그것이 지금 더 분명하기를 바란다. 문제는 * Cell_givenumberofvertices_parallel() * –

답변

0

난 아직도 당신이 달성하려고하는 일의 전체 그림도 이러한 설계를위한 이론적 근거를하지 않습니다.

어쨌든, 여기에 몇 가지 생각이 있습니다.

먼저, 일괄 작업을 호출 할 때 통신기의 모든 작업에서 호출해야합니다. 그렇지 않으면 일부 작업이 중단 될 수 있습니다.

둘째, Cell_givenumberofvertices_parallel()에서 MPI_Gather()MPI_Reduce()으로 바꿀 수 있습니다. 그리고 모든 계급의 메인 루프 인쇄하기 때문에, 난 당신이 정말 또한 그렇지 않으면 모든 계급이 MPI_COMM_WORLD에 집단을 호출하지하고이 중단됩니다, struct CellMPI_Comm * comm 필드를 추가 할 생각 MPI_Allreduce()

을 원하는 생각합니다.

셋째, 포인터 기능이 필요하지 않습니다.

셀이 하나의 작업에만있는 경우 통신은 MPI_COMM_SELF이어야하며 MPI_Allreduce()을 사용할 수 있으므로 두 개의 서브 루틴이 필요하지 않습니다.

마지막으로, 함수가 시간 경과에 따라 다른 값을 반환하는 방식을 볼 수 없으므로 초기화시 총 정점 수를 계산하고 새 필드로 저장할 수 있습니다.

예를 들어, 즉

struct Cell{ 
    unsigned localNbOfVertices; 
    unsigned totalNbOfVertices; 
    MPI_Comm comm; 
}; 

하고 메인 루프에서

, 당신은

for(i=0;i<numberofcells;i++){ 
    unsigned local=0, total; 
    MPI_Comm comm; 
    if(cells[i]) local=cells[i]->localNbOfVertices; 
    MPI_Allreduce(&local, &total, 1, MPI_UNSIGNED, MPI_SUM, MPI_COMM_WORLD); 
    if(cells[i] cells[i]->totalNbOfVertices = total; 
    printf("%i vertices in cell number %i \n",total,i); 
    if(cells[i]) MPI_Comm_split(MPI_COMM_WORLD, 0, world_rank, &cells[i]->comm); else MPI_Comm_split(MPI_COMM_WORLD, MPI_UNDEFINED, world_rank, &comm); 
    } 
+0

함수 내에 있습니다. 예, 작은 예제를 생성하기 위해 내 퀘스트에서 코드를 지나치게 단순화했을 수 있습니다. 나는 실제 응용 프로그램, 버텍스 위치 시간이 지남에 변경됩니다. 또한 * get/givenumberovertices() * 함수는 단순화 된 표현입니다. 실제 애플리케이션에서 사용되는 함수는 정점의 수와 위치에 따라 달라집니다. 구조체 Cell에 MPI_Comm * comm을 추가하면 내가 원하는 것을들을 수 있습니다. 그러나 나는 새로운 커뮤니케이터를 만드는 방법과 장소를 이해하기 위해 애 쓰고 있습니다. * createCell() *에서 처리하면 셀이 존재하는 다른 프로세서를 알 수 없습니다. –

+0

나는 내 대답을 커뮤니케이터 작성으로 업데이트했다. 모든 셀이 초기화되면 셀 커뮤니케이터를 만들어야합니다. –