2012-01-07 2 views
1

私のアプリケーションはLAM/MPIで動作しますが、OpenMPIでクラッシュします。対応する非ブロッキングプリミティブがOpenMPIによって許可される前にMPI_Waitを呼び出すか?

以下は私のコードの外観です。

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

ここでは、このエラーについて考えている人はいますか?

乾杯。

+1

この呼び出しの前に 'mpireq'と' mpistat'はどのように使われていますか?どのようにこの機能を呼びますか?すべてのプロセスがそれを呼び出しますか?より多くの文脈が役に立つでしょう。 – suszterpatt

+0

@suszterpattプロセス0を除く各プロセスのこの関数への最初の呼び出しでは、MPI_Waitはユニット化された要求と状態を読み取りますが、次の呼び出しでは、前の呼び出しで対応するMPI_Isendによって初期化されます。 –

+1

初期化されていないデータを決して関数に渡すことはありません。あなたがしたのは基本的に未定義の振る舞いです。あなたはLAM/MPIで幸運になりました。解決策をaswerとして投稿し、それを受け入れてください。 – suszterpatt

答えて

2

MPIはヌル要求の使用ハンドル可能 - MPI_REQUEST_NULL(C/C++ NULLポインタと混同しないように)MPI_WaitMPI_Testの呼び出しに。

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

が空の状態は常に0を返すとMPI_Get_countMPI_Get_elementsを呼び出す:ヌル要求ハンドルがMPI_Waitに渡されるたびに、コールはそれは次のようにステータスオブジェクトのフィールドが設定されている、空の状態ですぐに戻りますどのデータ型が提供されても問題ありません。 null要求ハンドルがMPI_Testに渡されると、呼び出しは空の状態で直ちに戻り、完了フラグはtrueに設定されます。

MPI_WaitMPI_Testの両方とも、完了した操作の要求ハンドルをMPI_REQUEST_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に設定(初期化)するだけで十分です。関数への最初の呼び出しに対する特別なテストは必要ではなく、コードの最初のバージョンは期待どおりに動作します。

1

suszterpattがCOMENTSに示すように、初期化されていないrequestMPI_Waitを呼び出すことは未定義であり、それがセグメンテーション違反することを必ずしも驚くことではありません。初期化されていない要求を使用すると、no-opと同等のではなくになります。初期化されていない構造体にはポインタが含まれています(たとえば、LAM/MPIでは、MPI_Request型は実際には構造体へのポインタでした)、初期化されていなければ、segfaultを得る可能性があります。

ノーオペレーションと同等のものを使用したい場合は、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; 
     /* ... */ 

} 
関連する問題