Do not block on explicit task depending on proxy task

Consider the following code:

    int dep;
    #pragma omp target nowait depend(out: dep)
    {
        sleep(1);
    }
    #pragma omp task depend(in: dep)
    {
        printf("Task with dependency\n");
    }
    printf("Doing some work...\n");

In its current state the runtime will block on the second task and not
continue execution.

Differential Revision: https://reviews.llvm.org/D23116

llvm-svn: 277992
This commit is contained in:
Jonas Hahnfeld 2016-08-08 10:08:14 +00:00
parent 69f8511f8f
commit bedc371c9d
3 changed files with 147 additions and 10 deletions

View File

@ -482,7 +482,8 @@ __kmpc_omp_task_with_deps( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_ta
bool serial = current_task->td_flags.team_serial || current_task->td_flags.tasking_ser || current_task->td_flags.final;
#if OMP_45_ENABLED
serial = serial && !(new_taskdata->td_flags.proxy == TASK_PROXY);
kmp_task_team_t * task_team = thread->th.th_task_team;
serial = serial && !(task_team && task_team->tt.tt_found_proxy_tasks);
#endif
if ( !serial && ( ndeps > 0 || ndeps_noalias > 0 )) {
@ -507,14 +508,8 @@ __kmpc_omp_task_with_deps( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_ta
return TASK_CURRENT_NOT_QUEUED;
}
} else {
#if OMP_45_ENABLED
kmp_task_team_t * task_team = thread->th.th_task_team;
if ( task_team && task_team->tt.tt_found_proxy_tasks )
__kmpc_omp_wait_deps ( loc_ref, gtid, ndeps, dep_list, ndeps_noalias, noalias_dep_list );
else
#endif
KA_TRACE(10, ("__kmpc_omp_task_with_deps(exit): T#%d ignored dependencies for task (serialized)"
"loc=%p task=%p\n", gtid, loc_ref, new_taskdata ) );
KA_TRACE(10, ("__kmpc_omp_task_with_deps(exit): T#%d ignored dependencies for task (serialized)"
"loc=%p task=%p\n", gtid, loc_ref, new_taskdata ) );
}
KA_TRACE(10, ("__kmpc_omp_task_with_deps(exit): T#%d task had no blocking dependencies : "

View File

@ -622,6 +622,7 @@ __kmp_task_finish( kmp_int32 gtid, kmp_task_t *task, kmp_taskdata_t *resumed_tas
{
kmp_taskdata_t * taskdata = KMP_TASK_TO_TASKDATA(task);
kmp_info_t * thread = __kmp_threads[ gtid ];
kmp_task_team_t * task_team = thread->th.th_task_team; // might be NULL for serial teams...
kmp_int32 children = 0;
#if OMPT_SUPPORT
@ -678,6 +679,12 @@ __kmp_task_finish( kmp_int32 gtid, kmp_task_t *task, kmp_taskdata_t *resumed_tas
#if OMP_40_ENABLED
if ( taskdata->td_taskgroup )
KMP_TEST_THEN_DEC32( (kmp_int32 *)(& taskdata->td_taskgroup->count) );
#if OMP_45_ENABLED
}
// if we found proxy tasks there could exist a dependency chain
// with the proxy task as origin
if ( !( taskdata -> td_flags.team_serial || taskdata -> td_flags.tasking_ser ) || (task_team && task_team->tt.tt_found_proxy_tasks) ) {
#endif
__kmp_release_deps(gtid,taskdata);
#endif
}
@ -715,7 +722,11 @@ __kmp_task_finish( kmp_int32 gtid, kmp_task_t *task, kmp_taskdata_t *resumed_tas
if (resumed_task == NULL) {
resumed_task = taskdata->td_parent; // In a serialized task, the resumed task is the parent
}
else {
else
#if OMP_45_ENABLED
if ( !(task_team && task_team->tt.tt_found_proxy_tasks) )
#endif
{
// verify resumed task passed in points to parent
KMP_DEBUG_ASSERT( resumed_task == taskdata->td_parent );
}

View File

@ -0,0 +1,131 @@
// RUN: %libomp-compile -lpthread && %libomp-run
#include <stdio.h>
#include <omp.h>
#include <pthread.h>
#include "omp_my_sleep.h"
/*
An explicit task can have a dependency on a target task. If it is not
directly satisfied, the runtime should not wait but resume execution.
*/
// Compiler-generated code (emulation)
typedef long kmp_intptr_t;
typedef int kmp_int32;
typedef char bool;
typedef struct ident {
kmp_int32 reserved_1; /**< might be used in Fortran; see above */
kmp_int32 flags; /**< also f.flags; KMP_IDENT_xxx flags; KMP_IDENT_KMPC identifies this union member */
kmp_int32 reserved_2; /**< not really used in Fortran any more; see above */
#if USE_ITT_BUILD
/* but currently used for storing region-specific ITT */
/* contextual information. */
#endif /* USE_ITT_BUILD */
kmp_int32 reserved_3; /**< source[4] in Fortran, do not use for C++ */
char const *psource; /**< String describing the source location.
The string is composed of semi-colon separated fields which describe the source file,
the function and a pair of line numbers that delimit the construct.
*/
} ident_t;
typedef struct kmp_depend_info {
kmp_intptr_t base_addr;
size_t len;
struct {
bool in:1;
bool out:1;
} flags;
} kmp_depend_info_t;
struct kmp_task;
typedef kmp_int32 (* kmp_routine_entry_t)( kmp_int32, struct kmp_task * );
typedef struct kmp_task { /* GEH: Shouldn't this be aligned somehow? */
void * shareds; /**< pointer to block of pointers to shared vars */
kmp_routine_entry_t routine; /**< pointer to routine to call for executing task */
kmp_int32 part_id; /**< part id for the task */
} kmp_task_t;
#ifdef __cplusplus
extern "C" {
#endif
kmp_int32 __kmpc_global_thread_num ( ident_t * );
kmp_task_t*
__kmpc_omp_task_alloc( ident_t *loc_ref, kmp_int32 gtid, kmp_int32 flags,
size_t sizeof_kmp_task_t, size_t sizeof_shareds,
kmp_routine_entry_t task_entry );
void __kmpc_proxy_task_completed_ooo ( kmp_task_t *ptask );
kmp_int32 __kmpc_omp_task_with_deps ( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task,
kmp_int32 ndeps, kmp_depend_info_t *dep_list,
kmp_int32 ndeps_noalias, kmp_depend_info_t *noalias_dep_list );
kmp_int32
__kmpc_omp_task( ident_t *loc_ref, kmp_int32 gtid, kmp_task_t * new_task );
#ifdef __cplusplus
}
#endif
void *target(void *task)
{
my_sleep( 0.1 );
__kmpc_proxy_task_completed_ooo((kmp_task_t*) task);
return NULL;
}
pthread_t target_thread;
// User's code
int task_entry(kmp_int32 gtid, kmp_task_t *task)
{
pthread_create(&target_thread, NULL, &target, task);
return 0;
}
int main()
{
int dep;
/*
* Corresponds to:
#pragma omp target nowait depend(out: dep)
{
my_sleep( 0.1 );
}
*/
kmp_depend_info_t dep_info;
dep_info.base_addr = (long) &dep;
dep_info.len = sizeof(int);
// out = inout per spec and runtime expects this
dep_info.flags.in = 1;
dep_info.flags.out = 1;
kmp_int32 gtid = __kmpc_global_thread_num(NULL);
kmp_task_t *proxy_task = __kmpc_omp_task_alloc(NULL,gtid,17,sizeof(kmp_task_t),0,&task_entry);
__kmpc_omp_task_with_deps(NULL,gtid,proxy_task,1,&dep_info,0,NULL);
int first_task_finished = 0;
#pragma omp task shared(first_task_finished) depend(inout: dep)
{
first_task_finished = 1;
}
int second_task_finished = 0;
#pragma omp task shared(second_task_finished) depend(in: dep)
{
second_task_finished = 1;
}
// check that execution has been resumed and the runtime has not waited
// for the dependencies to be satisfied.
int error = (first_task_finished == 1);
error += (second_task_finished == 1);
#pragma omp taskwait
// by now all tasks should have finished
error += (first_task_finished != 1);
error += (second_task_finished != 1);
return error;
}