Директива OPENMP taskyield не дает задач в гибридной (openmp + mpi) программе

Есть две задачи. Один общается через mpi, а другой делает классные вещи. Я использую неблокирующие вызовы mpi, чтобы позволить выполняющемуся потоку выполнять другие задачи в ожидании информации. Но это не работает.

Небольшое объяснение кода. Если хотите, можете сразу перейти к коду. Это создает два процесса. Первый процесс будет находиться в спящем режиме в течение 10 секунд, а затем отправит данные через блокирующий вызов Второй процесс (это интересующий процесс) создаст два потока с общим целым числом (готово). Одна задача будет создана один раз, а другая - столько раз, сколько существует потоков (в данном случае 2). Первая задача будет получать данные с использованием неблокирующего вызова и должна давать результат, чтобы работающий поток мог выполнить другую задачу (но этого не происходит). Эта задача выполняется только одним потоком. Второе задание просто печатает некоторые интересные вещи. Эта задача создается обоими потоками.

Вот код:

if (rank == 0)
  {
    buffer[1000] = 5;
    sleep(10);
    printf("Process %d sent data\n", rank);
    MPI_Send(buffer, SIZE, MPI_DOUBLE, 1, 5, MPI_COMM_WORLD);
  }
  else if (rank == 1)
  {
#pragma omp parallel num_threads(2) shared (done)
    {
#pragma omp single nowait
      {
#pragma omp task
        {
          int flag = 0;
          printf("Thread %d is receiving data\n", omp_get_thread_num());
          MPI_Irecv(buffer, SIZE, MPI_DOUBLE, 0, 5, MPI_COMM_WORLD, &request);

          MPI_Test(&request, &flag, &status);
          while (flag == 0)
          {
            #pragma omp taskyield
            MPI_Test(&request, &flag, &status);
            printf("Thread %d is wasting time\n", omp_get_thread_num());
            sleep(1);
          }

          done=1;
          printf("Thread %d received data\n", omp_get_thread_num());
        }
      }

#pragma omp task 
      {
        printf("Thread %d entered to the cool task\n", omp_get_thread_num());
        while (done == 0)
        {
          printf("Thread %d is doing some cool stuff\n", omp_get_thread_num());
          sleep(1); /* Or not */
        }
      }
    }
  }

И вот вывод:

Thread 0 is receiving data
Thread 1 entered to the cool task
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Process 0 sent data
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 is wasting time
Thread 1 is doing some cool stuff
Thread 0 received data
Thread 0 entered to the cool task

Как вы можете видеть, поток 0 не входит в классную задачу, пока не завершит задачу коммуникации.

Команда компиляции:

mpicc -fopenmp pruebas.c -o prueba

Выполнение команды:

mpirun -np 2 --allow-run-as-root ./prueba (worry not, read below)

Дополнительная информация:

The program is being ran in a docker container with ubuntu.
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)
mpicc --show output: gcc -I/usr/lib/openmpi/include/openmpi/opal/mca/event/libevent2021/libevent -I/usr/lib/openmpi/include/openmpi/opal/mca/event/libevent2021/libevent/include -I/usr/lib/openmpi/include -I/usr/lib/openmpi/include/openmpi -pthread -Wl,-rpath -Wl,/usr/lib/openmpi/lib -Wl,--enable-new-dtags -L/usr/lib/openmpi/lib -lmpi

1 ответ

Решение

Спецификация OpenMP не требует, чтобы taskyield что-нибудь делает

Конструкция taskyield указывает, что текущая задача может быть приостановлена ​​в пользу выполнения другой задачи.

Таким образом, он позволяет перепланирование, но не требует этого. (Описание алгоритма планирования задач также ясно по этому вопросу). Таким образом, gcc имеет полное право не переносить расписание.

Тем не менее, я знаю, что среда LMP LLVM (и Intel) OpenMP действительно дает результат, и мы видим, что gcc генерирует вызов во время выполнения, поэтому есть вероятность, что будет достаточно просто использовать среду выполнения LLVM с вашим двоичным файлом. Или попробуйте clang или компиляторы Intel.

(Полное раскрытие: я работаю на Intel:-))

Другие вопросы по тегам