OpenMP вложенные задачи, 1 поток не выполняет задачи

Я делаю несколько тестов с простым кодом, который написан ниже. Проблема в том, что на четырехъядерной машине нагрузка составляет всего 75%. Четвертое ядро ​​бездействует, ничего не делая. В коде есть параллельная omp, затем одиночная omp, внутри которой поток генерирует задачу. Эта задача порождает множество задач для внуков. Задача будет ожидать в барьере до тех пор, пока все ее дочерние элементы (внуки для потока в одной области) не завершатся, а поток, выполняющий одну область, ожидает другого барьера, пока не завершится его задача прямого потомка. Проблема в том, что поток, выполняющий один регион, не выполняет никаких задач внуков. Учитывая размер блока, который я использую, я создаю тысячи задач, так что это не проблема доступного параллелизма.

Я неправильно понимаю задачи OpenMP? Связано ли это с задачей, ожидающей только непосредственных детей? Если так, как я мог заставить свободный поток выполнить доступную работу? Представьте, что я хотел бы создавать задачи с зависимостями, как в OpenMP 4.0, тогда я не смог бы использовать все потоки, доступные с зависимостями. Барьер в родительской задаче был бы необходим, поскольку я не хотел бы освобождать следующие задачи, зависящие от него, пока все его дочерние элементы не закончатся.

#include <iostream>
#include <cstdlib>

#include <omp.h>

using namespace std;

#define VECSIZE 200000000

float* A;
float* B;
float* C;

void LoopDo(int start, int end) {
    for (int i = start; i < end; i++)
    {
        C[i] += A[i]*B[i];
        A[i] *= (B[i]+C[i]);
        B[i] = C[i] + A[i];
        C[i] *= (A[i]*C[i]);
        C[i] += A[i]*B[i];
        C[i] += A[i]*B[i];
        ....
    }


void StartTasks(int bsize)
{
    int nthreads = omp_get_num_threads();
    cout << "bsize is: " << bsize << endl;
    cout << "nthreads is: " << nthreads << endl;
    #pragma omp task default(shared)
    {
        for (int i =0; i <VECSIZE; i+=bsize)
        {
            #pragma omp task default(shared) firstprivate(i,bsize)
            LoopDo(i,i+bsize);
            if (i + bsize >= VECSIZE) bsize = VECSIZE - i;
        }
        cerr << "Task creation ended" << cerr;
        #pragma omp taskwait
    }
    #pragma omp taskwait
}


int main(int argc, char** argv)
{
    A = (float*)malloc(VECSIZE*sizeof(float));
    B = (float*)malloc(VECSIZE*sizeof(float));
    C = (float*)malloc(VECSIZE*sizeof(float));
    int bsize = atoi(argv[1]);
    for (int i = 0; i < VECSIZE; i++)
    {
        A[i] = i; B[i] = i; C[i] = i;
    }
    #pragma omp parallel
    {
        #pragma omp single
        {
            StartTasks(bsize);
        } 
    }
    free(A);
    free(B);
    free(C);
    return 0;
}

РЕДАКТИРОВАТЬ:

Я протестировал с ICC 15.0, и он использует все ядра моей машины. Хотя ICC разветвляет 5 потоков вместо 4, как GCC. Пятый поток ICC остается свободным.

РЕДАКТИРОВАТЬ 2: Следующее изменение, добавив цикл с таким количеством задач верхнего уровня, сколько потоков, получает все потоки с задачами. Если задачи верхнего уровня

 for (int i = 0; i<nthreads;i++)
 {
    #pragma omp task default(shared)
    {
        for (int i =0; i <VECSIZE; i+=bsize)
        {
            #pragma omp task default(shared) firstprivate(i,bsize)
            LoopDo(i,i+bsize);
            if (i + bsize >= VECSIZE) bsize = VECSIZE - i;
        }
        cerr << "Task creation ended" << cerr;
        #pragma omp taskwait
    }
  }
  #pragma omp taskwait

0 ответов

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