2016-12-19 12 views
0

Обзор: Я тестирую, что тип данных, созданный с использованием MPI_Type_create_struct(), является правильным и, следовательно, отправляет правильные значения. У меня возникают проблемы с получением значений, хранящихся в массивах, для передачи на другие процессоры. Я думаю, что это, вероятно, проблема с адресами памяти массивов в каждой связанной структуре и смещениями, хранящимися в индексах массива [], используемых для создания типа данных mpibound.Использование MPI_Type_create_struct() для переноса структур, содержащих динамические массивы, в C

Проблема: Я работаю над программой, использующей MPI, и моей конечной целью является использование MPI_Gatherv() для сбора значений из массива структур, называемых bound, которые описаны ниже.

struct bound { 
    int  n; 
    char* name; 
    double* lat; 
    double* lon; 
}; 

Я создал тестовую программу, чтобы убедиться, что я использовал MPI_Type_create_struct() правильно. Функция, в которой я называю MPI_Type_create_struct(), записывается ниже.

void CreateBoundType (struct bound a_bound) { 
    int blocklens[4];    /*Block Lengths of data in structure*/ 
    MPI_Datatype old_types[4];  /*Data types of data in structure*/ 
    MPI_Aint indices[4];   /*Byte displacement of each piece of data*/ 
    MPI_Aint addr1, addr2, addr3, addr4, baseaddr; 

    /*Set block lengths*/ 
    blocklens[0] = 1; 
    blocklens[1] = 10; 
    blocklens[2] = NPT_MAX; 
    blocklens[3] = NPT_MAX; 

    /*Set Data Types*/ 
    old_types[0] = MPI_INT; 
    old_types[1] = MPI_CHAR; 
    old_types[2] = MPI_DOUBLE; 
    old_types[3] = MPI_DOUBLE; 

    /*Set byte displacement for each piece of data in structure*/ 
    /*!!!!!I expect that the following 8 lines cause my problem!!!!!!*/ 
    MPI_Get_address (&a_bound,   &baseaddr); 
    MPI_Get_address (&a_bound.num_pts, &addr1); 
    MPI_Get_address (a_bound.label, &addr2); 
    MPI_Get_address (a_bound.lat,  &addr3); 
    MPI_Get_address (a_bound.lon,  &addr4); 
    indices[0] = addr1 - baseaddr; 
    indices[1] = addr2 - baseaddr; 
    indices[2] = addr3 - baseaddr; 
    indices[3] = addr4 - baseaddr; 

    /*Create structure type in MPI so that we can transfer boundaries between nodes*/ 
    MPI_Type_create_struct(4,blocklens,indices,old_types,&mpibound); 
    MPI_Type_commit(&mpibound); 
    return; 
} 

Когда я пытаюсь использовать тип данных я создал (который является глобальной переменной, mpibound), в вызове MPI_Bcast() значения, хранящиеся в массивах, которые являются частью буферной структуры, я использую не обновляются, но целочисленное значение n (n - длина массивов) действительно изменяется на всех процессорах. Поэтому я думаю, что моя проблема имеет какое-то отношение к смещениям (индексы [4]), которые используются для определения mpibound.

Ниже я написал основную функцию, которая показывает, как я называю эту функцию и настраиваю структуры. (Я опустил звонки в MPI_Init и другие подобные функции, чтобы держать его коротким, как я могу)

int main (int argc, char **argv) { 

    /*Initialise MPI etc*/... 

    /*Create structure to broadcast*/ 
    struct bound my_bound; 
    my_bound.name = strdup(string); 
    my_bound.lat = malloc(NPT_MAX*sizeof(double)); 
    my_bound.lon = malloc(NPT_MAX*sizeof(double)); 
    if(rank == 0) { 
     my_bound.n  = 5; 
     my_bound.lat[0] = 2.6; 
     my_bound.lon[0] = 4.2; 
    } 

    /*Call the function that creates the type mpibound*/ 
    CreateBoundType(my_bound); 

    /*Create buffer to be used in a Broadcast from the root processor (rank 0)*/ 
    struct bound *buff = malloc(sizeof(struct bound)); 
    buff->lat = malloc(NPT_MAX*sizeof(double)); 
    buff->lon = malloc(NPT_MAX*sizeof(double)); 
    buff = &my_bound; 

    /*Cast values in buffer from proc 0 to all others*/ 
    MPI_Bcast(buff,1,mpibound,0,MPI_COMM_WORLD); 

    /*Print values and checks, free memory etc*/... 

    return(EXIT_SUCCESS); 
} 

Положив несколько заявлений печати после вызова MPI_Bcast показывает, что на проках с рангами> 0, то значениями n обновляется до этой трансляции с ранга 0, но первый элемент массивов lat и lon по-прежнему равен 0.

Если вы можете мне помочь, я очень благодарен за то, что он боролся с этим в течение нескольких дней! Я старался держать это как можно короче, и это лучшая версия, которую я смог создать.

Спасибо за чтение!

+1

Ваш код имеет мало смысла. Вы выделяете две структуры и некоторую память для обоих массивов, но затем вы полностью выбрасываете память для второго, делая 'buff = & my_bound'. В любом случае, пожалуйста, подготовьте надлежащий [mcve] и более конкретный ожидаемый и фактический результат. – Zulan

+1

Я вернулся @Zulan до его комментария. Ваш код пронизан ошибками, и я думаю, что это больше, чем проблема MPI, это фундаментальное понимание C, которое вы пропустите здесь. После того, как у вас есть основы C, вы можете начать повышаться, пытаясь решить MPI, но язык C определенно является необходимым условием, если вы хотите запрограммировать в MPI + C. – Gilles

ответ

1

Как отметил Зулан, в вашем коде есть некоторые вещи, которые не имеют никакого смысла. Но главная проблема заключается

void CreateBoundType (struct bound a_bound) { 
//     HERE HERE HERE HERE 

Вы передаете структуру по стоимости, что означает, что тип данных MPI mpibound строится из адресов памяти копии значения. Копия содержит те же значения указателя для label, lat и lon, но база будет расположена где-то в другом месте. Поэтому вы не можете использовать этот тип данных для отправки экземпляра структуры в main, поскольку смещения недействительны для него.

Вместо этого вам следует передать структуру по адресу. Изменения минимальны:

void CreateBoundType (struct bound *a_bound) { 
    ... 
    MPI_Get_address(a_bound,   &baseaddr); 
    MPI_Get_address(&a_bound->n, &addr1); 
    MPI_Get_address(a_bound->label, &addr2); 
    MPI_Get_address(a_bound->lat,  &addr3); 
    MPI_Get_address(a_bound->lon,  &addr4); 
    ... 
} 

... 
/*Call the function that creates the type mpibound*/ 
CreateBoundType(&my_bound); 
... 

Обратите внимание, что вы не сможете достичь своей конечной цели, чтобы собрать (v) такие структуры, как смещения действительны только для одного экземпляра в то время как операции сбора создает массив. Каждый элемент массива, вероятно, будет иметь разные смещения и поэтому потребует отдельный тип данных MPI.

Поскольку вы тем не менее выделяете полный объем памяти для каждого из lat и lon, почему бы просто не использовать массивы в структуре?

struct bound { 
    int  n; 
    char name[10]; 
    double lat[NPT_MAX]; 
    double lon[NPT_MAX]; 
}; 

Не забудьте изменить размер структуры типа данных MPI после его создания в sizeof(struct bound) с помощью MPI_Type_create_resized.

Также обратите внимание, что в C указатель на структуру является указателем на его первый элемент, поэтому нет необходимости вычислять смещение n явно - гарантированно будет 0 языком.