// RUN: %libomp-compile-and-run // The runtime currently does not get dependency information from GCC. // UNSUPPORTED: gcc // Tests OMP 5.x task dependence "omp_all_memory", // emulates compiler codegen versions for new dep kind // // Task tree created: // task0 - task1 (in: i1, i2) // \ // task2 (inoutset: i2), (in: i1) // / // task3 (omp_all_memory) via flag=0x80 // / // task4 - task5 (in: i1, i2) // / // task6 (omp_all_memory) via addr=-1 // / // task7 (omp_all_memory) via flag=0x80 // / // task8 (in: i3) // #include #include #ifdef _WIN32 #include #define mysleep(n) Sleep(n) #else #include #define mysleep(n) usleep((n)*1000) #endif // to check the # of concurrent tasks (must be 1 for MTX, <3 for other kinds) static int checker = 0; static int err = 0; #ifndef DELAY #define DELAY 100 #endif // --------------------------------------------------------------------------- // internal data to emulate compiler codegen typedef struct DEP { size_t addr; size_t len; unsigned char flags; } dep; #define DEP_ALL_MEM 0x80 typedef struct task { void** shareds; void* entry; int part_id; void* destr_thunk; int priority; long long device_id; int f_priv; } task_t; #define TIED 1 typedef int(*entry_t)(int, task_t*); typedef struct ID { int reserved_1; int flags; int reserved_2; int reserved_3; char *psource; } id; // thunk routine for tasks with ALL dependency int thunk_m(int gtid, task_t* ptask) { int lcheck, th; #pragma omp atomic capture lcheck = ++checker; th = omp_get_thread_num(); printf("task m_%d, th %d, checker %d\n", ptask->f_priv, th, lcheck); if (lcheck != 1) { // no more than 1 task at a time err++; printf("Error m1, checker %d != 1\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; // must still be equal to 1 if (lcheck != 1) { err++; printf("Error m2, checker %d != 1\n", lcheck); } #pragma omp atomic --checker; return 0; } // thunk routine for tasks with inoutset dependency int thunk_s(int gtid, task_t* ptask) { int lcheck, th; #pragma omp atomic capture lcheck = ++checker; // 1 th = omp_get_thread_num(); printf("task 2_%d, th %d, checker %d\n", ptask->f_priv, th, lcheck); if (lcheck != 1) { // no more than 1 task at a time err++; printf("Error s1, checker %d != 1\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; // must still be equal to 1 if (lcheck != 1) { err++; printf("Error s2, checker %d != 1\n", lcheck); } #pragma omp atomic --checker; return 0; } #ifdef __cplusplus extern "C" { #endif int __kmpc_global_thread_num(id*); task_t *__kmpc_omp_task_alloc(id *loc, int gtid, int flags, size_t sz, size_t shar, entry_t rtn); int __kmpc_omp_task_with_deps(id *loc, int gtid, task_t *task, int ndeps, dep *dep_lst, int nd_noalias, dep *noalias_lst); static id loc = {0, 2, 0, 0, ";file;func;0;0;;"}; #ifdef __cplusplus } // extern "C" #endif // End of internal data // --------------------------------------------------------------------------- int main() { int i1,i2,i3; omp_set_num_threads(8); omp_set_dynamic(0); #pragma omp parallel { #pragma omp single nowait { dep sdep[2]; task_t *ptr; int gtid = __kmpc_global_thread_num(&loc); int t = omp_get_thread_num(); #pragma omp task depend(in: i1, i2) { // task 0 int lcheck, th; #pragma omp atomic capture lcheck = ++checker; // 1 or 2 th = omp_get_thread_num(); printf("task 0_%d, th %d, checker %d\n", t, th, lcheck); if (lcheck > 2 || lcheck < 1) { err++; // no more than 2 tasks concurrently printf("Error1, checker %d, not 1 or 2\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; // 1 or 2 if (lcheck > 2 || lcheck < 1) { #pragma omp atomic err++; printf("Error2, checker %d, not 1 or 2\n", lcheck); } #pragma omp atomic --checker; } #pragma omp task depend(in: i1, i2) { // task 1 int lcheck, th; #pragma omp atomic capture lcheck = ++checker; // 1 or 2 th = omp_get_thread_num(); printf("task 1_%d, th %d, checker %d\n", t, th, lcheck); if (lcheck > 2 || lcheck < 1) { err++; // no more than 2 tasks concurrently printf("Error3, checker %d, not 1 or 2\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; // 1 or 2 if (lcheck > 2 || lcheck < 1) { err++; printf("Error4, checker %d, not 1 or 2\n", lcheck); } #pragma omp atomic --checker; } // compiler codegen start // task2 ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_s); sdep[0].addr = (size_t)&i1; sdep[0].len = 0; // not used sdep[0].flags = 1; // IN sdep[1].addr = (size_t)&i2; sdep[1].len = 0; // not used sdep[1].flags = 8; // INOUTSET ptr->f_priv = t + 10; // init single first-private variable __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0); // task3 ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_m); sdep[0].addr = (size_t)&i1; // to be ignored sdep[0].len = 0; // not used sdep[0].flags = 1; // IN sdep[1].addr = 0; sdep[1].len = 0; // not used sdep[1].flags = DEP_ALL_MEM; // omp_all_memory ptr->f_priv = t + 20; // init single first-private variable __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0); // compiler codegen end #pragma omp task depend(in: i1, i2) { // task 4 int lcheck, th; #pragma omp atomic capture lcheck = ++checker; // 1 or 2 th = omp_get_thread_num(); printf("task 4_%d, th %d, checker %d\n", t, th, lcheck); if (lcheck > 2 || lcheck < 1) { err++; // no more than 2 tasks concurrently printf("Error5, checker %d, not 1 or 2\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; // 1 or 2 if (lcheck > 2 || lcheck < 1) { err++; printf("Error6, checker %d, not 1 or 2\n", lcheck); } #pragma omp atomic --checker; } #pragma omp task depend(in: i1, i2) { // task 5 int lcheck, th; #pragma omp atomic capture lcheck = ++checker; // 1 or 2 th = omp_get_thread_num(); printf("task 5_%d, th %d, checker %d\n", t, th, lcheck); if (lcheck > 2 || lcheck < 1) { err++; // no more than 2 tasks concurrently printf("Error7, checker %d, not 1 or 2\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; // 1 or 2 if (lcheck > 2 || lcheck < 1) { err++; printf("Error8, checker %d, not 1 or 2\n", lcheck); } #pragma omp atomic --checker; } // compiler codegen start // task6 ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_m); sdep[0].addr = (size_t)(-1); // omp_all_memory sdep[0].len = 0; // not used sdep[0].flags = 2; // OUT ptr->f_priv = t + 30; // init single first-private variable __kmpc_omp_task_with_deps(&loc, gtid, ptr, 1, sdep, 0, 0); // task7 ptr = __kmpc_omp_task_alloc(&loc, gtid, TIED, sizeof(task_t), 0, thunk_m); sdep[0].addr = 0; sdep[0].len = 0; // not used sdep[0].flags = DEP_ALL_MEM; // omp_all_memory sdep[1].addr = (size_t)&i3; // to be ignored sdep[1].len = 0; // not used sdep[1].flags = 4; // MUTEXINOUTSET ptr->f_priv = t + 40; // init single first-private variable __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0); // compiler codegen end #pragma omp task depend(in: i3) { // task 8 int lcheck, th; #pragma omp atomic capture lcheck = ++checker; // 1 th = omp_get_thread_num(); printf("task 8_%d, th %d, checker %d\n", t, th, lcheck); if (lcheck != 1) { err++; printf("Error9, checker %d, != 1\n", lcheck); } mysleep(DELAY); #pragma omp atomic read lcheck = checker; if (lcheck != 1) { err++; printf("Error10, checker %d, != 1\n", lcheck); } #pragma omp atomic --checker; } } // single } // parallel if (err == 0 && checker == 0) { printf("passed\n"); return 0; } else { printf("failed, err = %d, checker = %d\n", err, checker); return 1; } }