gpt4 book ai didi

c - 通过 MPI 发送 c 结构部分失败

转载 作者:行者123 更新时间:2023-11-30 15:46:23 25 4
gpt4 key购买 nike

我正在使用 MPI_Type_create_struct() 发送一个(粒子)结构,例如here ,或者详细解释here 。我正在收集所有进入特定过程的粒子,将它们memcpy()放入发送缓冲区中,并MPI_Isend()将它们放入。

到目前为止,一切都很好。 MPI_Iprob()'ing 消息给我发送的粒子的正确计数。因此,我 MPI_Recv() 缓冲区并提取数据(现在甚至通过一一复制结构)。无论我发送多少个粒子,只有第一个粒子的数据是正确的。

可能存在以下三种错误:

  1. 由于我像第一个链接一样使用了 offset of()MPI_Type_create_struct() 没有创建正确的结构映射。也许我的结构包含不可见的填充,如第二个链接中所述。
  2. 在将粒子复制到发送缓冲区并从接收缓冲区复制回来时,我犯了一些简单的错误(我确实打印了发送缓冲区 - 并且它有效 - 但也许我忽略了一些东西)
  3. 完全不同的东西。

(很抱歉代码的呈现方式非常丑陋,我无法以下降的方式呈现它。你会在 Github 上找到代码 here - 该行已经被标记了!)

这里是mpi数据类型的构造,

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。也许这就是解决方案的提示。

最佳答案

您的指针算术中有错误。 send_buf[i]已经是 pchase_particle_t * 类型因此send_buf[i] + j * sizeof(pchase_particle_t)不指向j i 的第一个元素-th 缓冲区而是到 j * sizeof(pchase_particle_t) -th 元素。因此,您的粒子不会连续存储在内存中,而是以 sizeof(pchase_particle_t) - 1 分隔。空数组元素。这些被发送而不是正确的粒子,因为 MPI_Send调用连续访问缓冲存储器。这同样适用于接收者的代码。

您在发送方代码中看不到错误,因为您的调试打印使用相同的不正确的指针算法,因此使用相同的步幅访问内存。我猜你的发送计数很小,并且你在数据段堆上分配了内存,否则你应该收到 SIGSEGV用于在数据打包过程的早期进行越界数组访问(例如在 memcpy 部分)。

解决方案:不要将数组索引乘以 sizeof(pchase_particle_t) .

关于c - 通过 MPI 发送 c 结构部分失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18453387/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com