0

ここMPI_Type_create_struct()で行われたように、またはここで詳細に説明されているように、(粒子)構造体を送信しています。特定のprocに向かうすべてのパーティクルを収集しています。それらは送信バッファに入れられます。memcpy()MPI_Isend()

ここまでは順調ですね。MPI_Iprob()メッセージを 'ing すると、送信されたパーティクルの正しいカウントが得られます。そのMPI_Recv()ため、バッファからデータを抽出します (構造体を 1 つずつコピーしても)。いくつの粒子を送っても、正しいのは最初の粒子のデータだけです。

次の 3 つの間違いが考えられます。

  1. 最初のリンクMPI_Type_create_struct()で like を使用しているため、構造体の適切なマップが作成されません。offset of()2 番目のリンクで説明されているように、構造体に非表示のパディングが含まれている可能性があります。
  2. パーティクルを送信バッファーにコピーしたり、受信バッファーからコピーしたりするときに、いくつかの単純な間違いを犯しています (送信バッファーを出力しますが、動作しますが、何かを見落としている可能性があります)。
  3. まったく違う何か。

(コードの表示が本当に見苦しくなって申し訳ありません。下降した方法で表示することができませんでした。コードはここにあります- 行は既にマークされています - Github にもあります!)

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++;
    }
  }
}

edit: reindented.. edit: 最初のパーティクルのデータのみが正しいということは、そのすべてのプロパティ (ID と座標) が送信されたパーティクルのデータと同じであることを意味します。ただし、その他はゼロで初期化されます。つまり、ID=0、x[0]=0.0、x[1]=0.0 です。それが解決のヒントになるかもしれません。

4

1 に答える 1

1

ポインター演算にエラーがあります。send_buf[i]はすでにタイプpchase_particle_t *であるため、 -th バッファーの -th 要素ではなく、 -th 要素をsend_buf[i] + j * sizeof(pchase_particle_t)指しています。したがって、パーティクルはメモリに連続して保存されるのではなく、空の配列要素で区切られます。コールはバッファ メモリに連続してアクセスするため、これらは正しいパーティクルの代わりに送信されます。同じことが受信機のコードにも当てはまります。jij * sizeof(pchase_particle_t)sizeof(pchase_particle_t) - 1MPI_Send

送信者コードにエラーは表示されません。これは、デバッグ プリントが同じ間違ったポインター演算を使用し、同じストライドを使用してメモリにアクセスするためです。送信数が少なく、データ セグメント ヒープにメモリが割り当てられていると思います。それ以外の場合は、データ パッキング プロセスの非常に早い段階で (たとえば、一部で) SIGSEGV、範囲外の配列アクセスを受け取る必要があります。memcpy

解決策: 配列インデックスに を掛けないでくださいsizeof(pchase_particle_t)

于 2013-08-28T14:53:58.423 に答える