如何正确产生/恢复OpenMP无关的任务? [英] How to yield/resume OpenMP untied tasks correctly?

查看:180
本文介绍了如何正确产生/恢复OpenMP无关的任务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个小型C程序来评估OpenMP在任务中出现空闲时间(例如,等待通信数据)时屈服于另一任务的能力:

I wrote a small C program to assess OpenMP's capability to yield to another task when idle time in a task occurs (e.g. wait for communicated data):

#include <stdio.h>
#include <sys/time.h>
#include <omp.h>

#define NTASKS 10

double wallClockTime(void) {

    struct timeval t;

    gettimeofday(&t, NULL);

    return (double)(t.tv_sec + t.tv_usec/1000000.);
}

void printStatus(char *status, int taskNum, int threadNum) {

#pragma omp critical(printStatus)
    {
        int i;
        for (i = 0; i < taskNum; i++) printf("    ");
        printf(" %s%i \n", status, threadNum);
    }
}

void task(int taskNum) {

    // "r"un task
    printStatus("r", taskNum, omp_get_thread_num());
    sleep(1);

    // "s"leeping task that can yield
    printStatus("s", taskNum, omp_get_thread_num());
    double idleStartTime = wallClockTime();
    while (wallClockTime() < idleStartTime + 1) {
#pragma omp taskyield
    }

    // "c"ontinue task
    printStatus("c", taskNum, omp_get_thread_num());
    sleep(1);
}


int main(int argc, char* argv[]) {

#pragma omp parallel
#pragma omp single nowait
    {
        int i;

        printf("thread %d is master\n\n", omp_get_thread_num());
        for (i = 0; i < NTASKS; i++) printf(" %02d ", i);
        printf("\n");

        for (i = 0; i < NTASKS; i++) {

#pragma omp task untied
            task(i);
        }
    }

    return 0;
}

我使用了Intel C编译器17.0.4.这是具有3个线程的运行的输出:

I used Intel C compiler 17.0.4. Here is the output from a run with 3 threads:

thread 0 is master

 00  01  02  03  04  05  06  07  08  09 
 r1 
                                     r0 
     r2 
 s1 
                                     s0 
     s2 
                                 r0 
 c1 
     c2 
                                 s0 
                             r0 
         r1 
             r2 
                             s0 
                         r0 
         s1 
             s2 
                         s0 
                     r0 
         c1 
             c2 
                     s0 
                 r0 
                 s0 
                 c0 
                     c0 
                         c0 
                             c0 
                                 c0 
                                     c0

线程1和2根本不屈服,但是它们坚持执行分配的任务.我还希望线程1和2在已挂起的未绑定任务04 ... 09上继续执行,但是这些仅由主线程0处理,而其他线程处于空闲状态.

Thread 1 and 2 do not yield at all, but they stick to their assigned task instead. I would also expect threads 1 and 2 to continue on the suspended untied tasks 04 ... 09, but these are only handled by master thread 0 while the other threads are idle.

是否必须以其他方式发布或产生任务,还是(尚)英特尔的OpenMP运行时无法处理此任务?顺便说一句,GNU gcc 4.9.2完全不能从任务中产生.

Do the tasks have to be issued or yielded in a different way, or is Intel's OpenMP runtime not (yet) capable to handle this? Btw., GNU gcc 4.9.2 does not yield from tasks at all.

推荐答案

我认为您的代码很好,这是一个实现问题.实际上,在LLVM OpenMP实现中-与Intel的实现非常相关-在两周前完成了一次提交,它可以解决您的问题.在我的测试中,仅通过设置LD_LIBRARY_PATH并产生期望的结果,c的当前libiomp5.so(从主干构建)就与icc 17.0.4兼容.

I think your code is just fine and this is an implementation issue. In fact in the LLVM OpenMP implementation - which is very much related to Intel's - pushed a commit two weeks ago that fixes your issue. In my tests, clang's current libiomp5.so (built from trunk) was compatible with icc 17.0.4 just by setting LD_LIBRARY_PATH and produces the desired result.

thread 0 is master

 00  01  02  03  04  05  06  07  08  09 
                                     r0 
 r2 
     r1 
                                     s0 
                                 r0 
 s2 
         r2 
     s1 
             r1 
                                 s0 
                             r0 
         s2 
                 r2 
             s1 
                     r1 
                             s0 
                         r0 
                 s2 
                     s1 
                 c2 
                         s0 
                     c1 
                         c0 
         c2 
             c1 
                             c0 
 c2 
     c1 
                                 c0 
                                     c0 

我还可以确认gcc完全没有产生,但没有详细介绍.

I can also confirm that gcc does not yield at all, but haven't looked in detail.

我不知道该更改是否以及何时可以合并到英特尔提供的库中.

I have no idea if and when the change might be merged into library shipped by Intel.

更新:您的行为仍然不是最佳的,您是对的.从代码的简短浏览来看,libiomp似乎支持绑定任务的概念,但是在taskwait期间不重新排队该任务,而是仅执行另一个任务,并将暂停的任务的上下文保留在堆栈中.我怀疑适当的支持将需要更多的编译器支持(某种连续性),而不仅仅是生成库调用.

Update: You are right that the behavior is still not optimal. From briefly looking through the code it seems that libiomp supports the notion of tied tasks, but does not requeue the task during a taskwait but instead just executes another task and retains the context of the suspended task on the stack. I suspect a proper support would require more heavy compiler support (continuations of a sort) rather than just generating library calls.

同样,您所做的一切都正确,但是编译器/运行时不够复杂,无法支持标准的 (行为完全符合标准).还要注意,对于所描述的libiomp当前行为,任务甚至不需要解开,因为到目前为止它们只是排队.除了拆分/链接任务之外,似乎没有一种简单的方法来获得所需的内容.

Again, you are doing everything right, but the compiler / runtime is not sophisticated enough to support what the standard allows (the behavior is fully standards compliant). Also note that for the described current behavior of libiomp, the tasks don't even need to be untied, since they are only queue so far. There doesn't seem to be an easy way to get what you want short of splitting up / chaining tasks.

这篇关于如何正确产生/恢复OpenMP无关的任务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆