Вызов MPI_Wait перед любыми соответствующими неблокирующими примитивами не разрешен OpenMPI? - PullRequest
1 голос
/ 07 января 2012

Мое приложение работает с 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 в конце функции.

Iпродолжайте получать ошибку сегментации изнутри MPI_Wait при каждом запуске с OpenMPI.

Я исправил это, проверив, вызывается ли функция в первый раз с логической переменной * 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 );    
    }

Кто-нибудь здесь имеет какое-либо представление об этой ошибке?

Приветствия.

Ответы [ 2 ]

3 голосов
/ 08 апреля 2014

MPI позволяет использовать дескрипторы пустых запросов - MPI_REQUEST_NULL (не путать с указателями C / C ++ NULL) в вызовах MPI_Wait и MPI_Test. Всякий раз, когда дескриптор нулевого запроса передается в MPI_Wait, вызов немедленно возвращается с пустым состоянием, то есть поля объекта состояния устанавливаются следующим образом:

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

Вызов MPI_Get_count и MPI_Get_elements с пустым статусом всегда возвращает 0, независимо от того, какой тип данных предоставлен. Всякий раз, когда дескриптор нулевого запроса передается на MPI_Test, вызов немедленно возвращается с пустым статусом, а флаг завершения устанавливается на true.

И MPI_Wait, и MPI_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 голос
/ 07 января 2012

Как следует из комментария suszterpatt, вызов MPI_Wait с неинициализированным request не определен, и не обязательно удивительно, что он вызывает ошибки.Использование неинициализированного запроса не эквивалентно запрету.Неинициализированная структура содержит указатели (например, в LAM / MPI тип MPI_Request сам по себе являлся указателем на структуру), и если он не инициализирован, велика вероятность, что вы получите ошибку сегмента.

Если вы хотите что-то, что эквивалентно запрету, вы можете использовать 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;
      /* ... */

}
...