156 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			156 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
| // RUN: %libomp-compile-and-run
 | |
| 
 | |
| // Tests OMP 5.0 task dependences "mutexinoutset", emulates compiler codegen
 | |
| // Mutually exclusive tasks get input dependency info array sorted differently
 | |
| //
 | |
| // Task tree created:
 | |
| //      task0 task1
 | |
| //         \    / \
 | |
| //         task2   task5
 | |
| //           / \
 | |
| //       task3  task4
 | |
| //       /   \
 | |
| //  task6 <-->task7  (these two are mutually exclusive)
 | |
| //       \    /
 | |
| //       task8
 | |
| //
 | |
| #include <stdio.h>
 | |
| #include <omp.h>
 | |
| 
 | |
| #ifdef _WIN32
 | |
| #include <windows.h>
 | |
| #define mysleep(n) Sleep(n)
 | |
| #else
 | |
| #include <unistd.h>
 | |
| #define mysleep(n) usleep((n)*1000)
 | |
| #endif
 | |
| 
 | |
| static int checker = 0; // to check if two tasks run simultaneously
 | |
| static int err = 0;
 | |
| #ifndef DELAY
 | |
| #define DELAY 100
 | |
| #endif
 | |
| 
 | |
| // ---------------------------------------------------------------------------
 | |
| // internal data to emulate compiler codegen
 | |
| typedef int(*entry_t)(int, int**);
 | |
| typedef struct DEP {
 | |
|   size_t addr;
 | |
|   size_t len;
 | |
|   int flags;
 | |
| } dep;
 | |
| typedef struct ID {
 | |
|   int reserved_1;
 | |
|   int flags;
 | |
|   int reserved_2;
 | |
|   int reserved_3;
 | |
|   char *psource;
 | |
| } id;
 | |
| 
 | |
| int thunk(int gtid, int** pshareds) {
 | |
|   int t = **pshareds;
 | |
|   int th = omp_get_thread_num();
 | |
|   #pragma omp atomic
 | |
|     ++checker;
 | |
|   printf("task __%d, th %d\n", t, th);
 | |
|   if (checker != 1) {
 | |
|     err++;
 | |
|     printf("Error1, checker %d != 1\n", checker);
 | |
|   }
 | |
|   mysleep(DELAY);
 | |
|   if (checker != 1) {
 | |
|     err++;
 | |
|     printf("Error2, checker %d != 1\n", checker);
 | |
|   }
 | |
|   #pragma omp atomic
 | |
|     --checker;
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C" {
 | |
| #endif
 | |
| int __kmpc_global_thread_num(id*);
 | |
| extern int** __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, int **task, int nd, dep *dep_lst,
 | |
|                           int nd_noalias, dep *noalias_dep_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,i4;
 | |
|   omp_set_num_threads(2);
 | |
|   #pragma omp parallel
 | |
|   {
 | |
|     #pragma omp single nowait
 | |
|     {
 | |
|       dep sdep[2];
 | |
|       int **ptr;
 | |
|       int gtid = __kmpc_global_thread_num(&loc);
 | |
|       int t = omp_get_thread_num();
 | |
|       #pragma omp task depend(in: i1, i2)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 0_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY); }
 | |
|       #pragma omp task depend(in: i1, i3)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 1_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY); }
 | |
|       #pragma omp task depend(in: i2) depend(out: i1)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 2_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY); }
 | |
|       #pragma omp task depend(in: i1)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 3_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY); }
 | |
|       #pragma omp task depend(out: i2)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 4_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY+5); } // wait a bit longer than task 3
 | |
|       #pragma omp task depend(out: i3)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 5_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY); }
 | |
| // compiler codegen start
 | |
|       // task1
 | |
|       ptr = __kmpc_omp_task_alloc(&loc, gtid, 0, 28, 16, thunk);
 | |
|       sdep[0].addr = (size_t)&i1;
 | |
|       sdep[0].len = 0;   // not used
 | |
|       sdep[0].flags = 4; // mx
 | |
|       sdep[1].addr = (size_t)&i4;
 | |
|       sdep[1].len = 0;   // not used
 | |
|       sdep[1].flags = 4; // mx
 | |
|       **ptr = t + 10; // init single shared variable
 | |
|       __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
 | |
| 
 | |
|       // task2
 | |
|       ptr = __kmpc_omp_task_alloc(&loc, gtid, 0, 28, 16, thunk);
 | |
|       // reverse pointers - library should sort them uniquely
 | |
|       sdep[0].addr = (size_t)&i4;
 | |
|       sdep[1].addr = (size_t)&i1;
 | |
|       **ptr = t + 20; // init single shared variable
 | |
|       __kmpc_omp_task_with_deps(&loc, gtid, ptr, 2, sdep, 0, 0);
 | |
| // compiler codegen end
 | |
|       #pragma omp task depend(in: i1)
 | |
|       { int th = omp_get_thread_num();
 | |
|         printf("task 8_%d, th %d\n", t, th);
 | |
|         mysleep(DELAY); }
 | |
|     } // single
 | |
|   } // parallel
 | |
|   if (err == 0) {
 | |
|     printf("passed\n");
 | |
|     return 0;
 | |
|   } else {
 | |
|     printf("failed\n");
 | |
|     return 1;
 | |
|   }
 | |
| }
 |