1

私のアプリケーションはLAM/MPIで動作しますが、OpenMPIでクラッシュします。

以下は私のコードがどのように見えるかです。

void Comm::nonblocking_send( int s_idx , int e_idx )
{      
      MPI_Wait(&mpireq,&mpistat);


      buffer.clear();

      list<class vertex*>::iterator vit;

      for( vit=our_dag->cur_block_intmeds.begin() ; vit!=our_dag->cur_block_intmeds.end() ; vit++ )
      {
        vertex * v = (*vit);

        list<class edge*> in_edges = v->in_edges;
        list<class edge*>::iterator eit;

        for( eit=in_edges.begin() ; eit!=in_edges.end() ; eit++ )
        {
            int x_idx = (*eit)->src->idx;
            int     y_idx = (*eit)->tgt->idx;
            double  dydx  = (*eit)->partial;

            struct partial * p = new partial();
            //ownership info
            p->rank = our_dag->rank;
            //structural info
            p->x_idx = x_idx;
            p->y_idx = y_idx;
            p->dydx = dydx;
            //block info
            p->block_idx = our_dag->block_idx;
            p->s_idx = s_idx;
            p->e_idx = e_idx;

            buffer.push_back(*p);

            delete p;
        }
      }

      MPI_Isend( &buffer[0] , buffer.size() , MPI_PARTIAL , 0 , DAG_MERG_REQ ,   MPI_COMM_WORLD , &mpireq );    
}

ご覧のとおり、関数の開始時にMPI_Waitが呼び出され、続いていくつかの計算が行われ、最終的には関数の終了時にそれぞれのMPI_ISendが呼び出されます。

OpenMPIで実行するたびに、MPI_Wait内からセグメンテーション違反が発生し続けます。

次のようにブール変数*first_time*を使用して関数が初めて呼び出されるかどうかを確認することで、これを修正しました。

void Comm::nonblocking_send( int s_idx , int e_idx )
    {      
          if(first_time)

               first_time = false;
          else

               MPI_Wait(&mpireq,&mpistat);


          buffer.clear();

          list<class vertex*>::iterator vit;

          for( vit=our_dag->cur_block_intmeds.begin() ; vit!=our_dag->cur_block_intmeds.end() ; vit++ )
          {
            vertex * v = (*vit);

            list<class edge*> in_edges = v->in_edges;
            list<class edge*>::iterator eit;

            for( eit=in_edges.begin() ; eit!=in_edges.end() ; eit++ )
            {
                int x_idx = (*eit)->src->idx;
                int     y_idx = (*eit)->tgt->idx;
                double  dydx  = (*eit)->partial;

                struct partial * p = new partial();
                //ownership info
                p->rank = our_dag->rank;
                //structural info
                p->x_idx = x_idx;
                p->y_idx = y_idx;
                p->dydx = dydx;
                //block info
                p->block_idx = our_dag->block_idx;
                p->s_idx = s_idx;
                p->e_idx = e_idx;

                buffer.push_back(*p);

                delete p;
            }
          }

          MPI_Isend( &buffer[0] , buffer.size() , MPI_PARTIAL , 0 , DAG_MERG_REQ ,   MPI_COMM_WORLD , &mpireq );    
    }

ここの誰かがこのエラーについて何か考えを持っていますか?

乾杯。

4

2 に答える 2

5

MPIでは、およびへの呼び出しでnull要求ハンドル(C / C ++ポインターMPI_REQUEST_NULLと混同しないでください)を使用できます。null要求ハンドルがに渡されると、呼び出しは空のステータスですぐに戻ります。つまり、ステータスオブジェクトのフィールドは次のように設定されます。NULLMPI_WaitMPI_TestMPI_Wait

.MPI_TAG = MPI_ANY_TAG
.MPI_SOURCE = MPI_ANY_SOURCE
.MPI_ERROR = MPI_SUCCESS

呼び出しMPI_Get_countMPI_Get_elements空のステータスは、提供されているデータ型に関係なく、常に0を返します。null要求ハンドルがに渡されるMPI_Testと、呼び出しは空のステータスですぐに戻り、完了フラグがに設定されtrueます。

両方ともMPI_WaitMPI_Test完了した操作の要求ハンドルをに設定しMPI_REQUEST_NULLます。エラーなしでnullハンドルを渡すことができるようにすると、悪影響を与えることなく、同じハンドル変数を使用して待機/テスト関数を繰り返し呼び出すことができます。

MPI_Isend(..., &req);
// req now contains a handle to the non-blocking send
MPI_Wait(&req, &status);
// The non-blocking send is first completed, then req is set to MPI_REQUEST_NULL
MPI_Wait(&req, &status);
// No-op, returns an empty status

したがって、この質問のような場合MPI_REQUEST_NULLは、コンストラクターで要求変数をに設定(初期化)するだけで十分です。関数の最初の呼び出しに特別なテストは必要なく、コードの最初のバージョンは期待どおりに機能します。

于 2014-04-08T08:34:17.980 に答える
1

suszterpattがコメントで示唆しているようにMPI_Wait、初期化されていない呼び出しrequestは定義されておらず、セグフォールトであることは必ずしも驚くべきことではありません。初期化されていないリクエストを使用することは、no-opと同等ではありません。初期化されていない構造体にはポインターが含まれ(たとえば、LAM / MPIでは、MPI_Requestタイプ自体が構造体へのポインターでした)、初期化されていない場合は、セグメンテーション違反が発生する可能性が高くなります。

no-opと同等のものが必要な場合はMPI_Waitall、カウント0で使用できます。

void Comm::nonblocking_send( int s_idx , int e_idx )
{     
      if (first_time) count = 0; 
      MPI_Waitall(count, &mpireq,&mpistat);

      /* ... */
      count = 1;
      first_time = false;
      /* ... */

}
于 2012-01-07T16:05:22.167 に答える