OpenMP嵌套任务,1个线程没有执行任务

时间:2015-05-01 16:40:30

标签: multithreading openmp gcc4.8

我正在使用下面写的简单代码进行一些测试。 问题是在四核机器中,我只有75%的负载。第四个核心是空转,什么都不做。代码有一个omp并行,然后是一个omp单个,其中线程生成一个任务。该任务产生了许多孙子任务。任务将在屏障中等待,直到其所有子节点(单个区域中的线程的孙子节点)完成,并且执行单个区域的线程在另一个屏障上等待,直到其直接后代任务完成。问题是执行单个区域的线程不执行任何孙子任务。鉴于我正在使用的块大小,我正在创建数千个任务,因此这不是可用并行性的问题。

我是否误解了OpenMP任务?是否与等待直接孩子的taskwait相关?如果是这样,我怎么能让空闲线程执行可用的工作?想象一下,我想在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线程而不是像GCC那样4线程。第五个ICC线程仍处于空闲状态。

编辑2: 以下更改,添加一个包含与线程一样多的顶级任务的循环,可以使所有线程完成任务。如果顶级任务&lt; ntthread然后在某些执行中,主线程将不执行任何任务并且将像以前一样保持空闲。 ICC将始终生成一个允许使用所有内核的二进制文件。

 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 个答案:

没有答案