2013-08-26 4 views
0

Я отправляю структуру (частицу), используя MPI_Type_create_struct(), как это сделано, например. here, или подробно объясняется here. Я собираю все частицы, которые идут к определенному процессу, memcpy() их в буфер отправки и MPI_Isend() их.Передача с struct через MPI частично частично

До сих пор так хорошо. MPI_Iprob() 'ing для сообщения дает мне правильное количество отправленных частиц. Так что я MPI_Recv() буфер и извлечение данных (теперь даже путем копирования структуры один за другим). Независимо от того, сколько частиц я посылаю, правильны только данные первых частиц.

Есть три возможных ошибки:

  1. MPI_Type_create_struct() не создает правильную карту моей структуры, из-за мое использование offset of() как в первом звене. Возможно, моя структура содержит не видимое дополнение, как объясняется во второй ссылке.
  2. Я делаю некоторые простые ошибки при копировании частиц в буфер отправки и из буфера приема обратно (я печатаю буфер отправки - и это работает, но, возможно, я что-то пропускаю)
  3. Что-то совсем другое.

(извините за очень некрасивое представление кода, я не мог управлять, чтобы представить его в спускаемом пути Вы найдете код here -. Линия уже отмеченная - на Github, тоже)

Здесь строительство МПИ типа данных,

typedef struct { 
     int     ID; 
     double    x[DIM]; 
} pchase_particle_t; 

const int   items = 2; 
int     block_lengths[2] = {1, DIM}; 
MPI_Datatype  mpi_types[2] = {MPI_INT, MPI_DOUBLE}; 
MPI_Aint   offsets[2]; 
offsets[0] = offsetof(pchase_particle_t, ID); 
offsets[1] = offsetof(pchase_particle_t, x); 
MPI_Type_create_struct(items, block_lengths, offsets, mpi_types, &W->MPI_Particle); 
MPI_Type_commit(&W->MPI_Particle); 

отправляющий

/* handle all mpi send/recv status data */ 
MPI_Request  *send_request = P4EST_ALLOC(MPI_Request, W->p4est->mpisize); 
MPI_Status   *recv_status = P4EST_ALLOC(MPI_Status, W->p4est->mpisize); 
/* setup send/recv buffers */ 
pchase_particle_t **recv_buf = P4EST_ALLOC(pchase_particle_t *, num_senders); 
pchase_particle_t **send_buf = P4EST_ALLOC(pchase_particle_t *, num_receivers); 
int     recv_count = 0, recv_length, flag, j; 

/* send all particles to their belonging procs */ 
for (i = 0; i < num_receivers; i++) { 
    /* resolve particle list for proc i */ 
    sc_list_t   *tmpList = *((sc_list_t **) sc_array_index(W->particles_to, receivers[i])); 
    pchase_particle_t * tmpParticle; 
    int     send_count = 0; 

    /* get space for the particles to be sent */ 
    send_buf[i] = P4EST_ALLOC(pchase_particle_t, tmpList->elem_count); 

    /* copy all particles into the send buffer and remove them from this proc */ 
    while(tmpList->first != NULL){ 
    tmpParticle = sc_list_pop(tmpList); 
    memcpy(send_buf[i] + send_count * sizeof(pchase_particle_t), tmpParticle, sizeof(pchase_particle_t)); 
    /* free particle */ 
    P4EST_FREE(tmpParticle); 
    /* update particle counter */ 
    send_count++; 
    } 

    /* print send buffer */ 
    for (j = 0; j < send_count; j++) { 
    pchase_particle_t *tmpParticle = send_buf[i] + j * sizeof(pchase_particle_t); 
    printf("[pchase %i sending] particle[%i](%lf,%lf)\n", W->p4est->mpirank, tmpParticle->ID, tmpParticle->x[0], tmpParticle->x[1]); 
    } 

    printf("[pchase %i sending] particle count: %i\n", W->p4est->mpirank, send_count); 
    /* send particles to right owner */ 
    mpiret = MPI_Isend(send_buf[i], send_count, W->MPI_Particle, receivers[i], 13, W->p4est->mpicomm, &send_request[i]); 
    SC_CHECK_MPI(mpiret); 
} 

и прием.

recv_count = 0; 
/* check for messages until all arrived */ 
while (recv_count < num_senders) { 
    /* probe if any of the sender has already sent his message */ 
    for (i = 0; i < num_senders; i++) { 
    MPI_Iprobe(senders[i], MPI_ANY_TAG, W->p4est->mpicomm, 
     &flag, &recv_status[i]); 
    if (flag) { 
     /* resolve number of particles receiving */ 
     MPI_Get_count(&recv_status[i], W->MPI_Particle, &recv_length); 
     printf("[pchase %i receiving message] %i particles arrived from sender %i with tag %i\n", 
      W->p4est->mpirank, recv_length, recv_status[i].MPI_SOURCE, recv_status[i].MPI_TAG); 
     /* get space for the particles to be sent */ 
     recv_buf[recv_count] = P4EST_ALLOC(pchase_particle_t, recv_length); 
     /* receive a list with recv_length particles */ 
     mpiret = MPI_Recv(recv_buf[recv_count], recv_length, W->MPI_Particle, recv_status[i].MPI_SOURCE, 
      recv_status[i].MPI_TAG, W->p4est->mpicomm, &recv_status[i]); 
     SC_CHECK_MPI(mpiret); 

     /* 
     * insert all received particles into the 
     * push list 
     */ 
     pchase_particle_t *tmpParticle; 
     for (j = 0; j < recv_length; j++) { 
     /* 
     * retrieve all particle details from 
     * recv_buf 
     */ 
     tmpParticle = recv_buf[recv_count] + j * sizeof(pchase_particle_t); 
     pchase_particle_t *addParticle = P4EST_ALLOC(pchase_particle_t,1); 
     addParticle->ID=tmpParticle->ID; 
     addParticle->x[0] = tmpParticle->x[0]; 
     addParticle->x[1] = tmpParticle->x[1]; 

     printf("[pchase %i receiving] particle[%i](%lf,%lf)\n", 
      W->p4est->mpirank, addParticle->ID, addParticle->x[0], addParticle->x[1]); 
     /* push received particle to push list and update world counter */ 
     sc_list_append(W->particle_push_list, addParticle); 
     W->n_particles++; 
     } 
     /* we received another particle list */ 
     recv_count++; 
    } 
    } 
} 

редактировать: отступы .. редактирования: данные только первое частиц является правильными, означает, что все его свойство (ID и координата) идентично, что отправленная частица. Однако остальные инициализируются нулями, то есть ID = 0, x [0] = 0,0, x [1] = 0,0. Возможно, это намек на решение.

+0

Это не отвечает на ваш вопрос, но если вы все равно сделаете копию своих данных, я бы рекомендовал вместо этого использовать 'MPI_Pack()'. – suszterpatt

ответ

0

В вашей арифметике указателя есть ошибка. send_buf[i] уже относится к типу pchase_particle_t * и поэтому send_buf[i] + j * sizeof(pchase_particle_t) не указывает на j-й элемент i-й буфер, а скорее на j * sizeof(pchase_particle_t)-й элемент. Таким образом, ваши частицы не хранятся смежно в памяти, а скорее разделены sizeof(pchase_particle_t) - 1 пустых элементов массива. Они отправляются вместо правильных частиц, потому что вызов MPI_Send обращается к буферной памяти смежно. То же самое относится к коду получателя.

Вы не видите ошибку в коде отправителя, потому что ваша отладочная печать использует ту же неправильную арифметику указателя и, следовательно, обращается к памяти с использованием того же шага. Я думаю, ваши подсчеты отправки невелики, и вы получаете память, выделенную на кучу сегмента данных, иначе вы должны были бы получить SIGSEGV для доступа к внеполосной матрице очень рано в процессе упаковки данных (например, в части memcpy).

Разрешение: не умножайте индекс массива на sizeof(pchase_particle_t).

Смежные вопросы