1 // RUN: %libomp-compile-and-run 2 // RUN: %libomp-compile && env KMP_TASKLOOP_MIN_TASKS=1 %libomp-run 3 // REQUIRES: openmp-4.5 4 #include <stdio.h> 5 #include <omp.h> 6 #include "omp_my_sleep.h" 7 8 #define N 4 9 #define GRAIN 10 10 #define STRIDE 3 11 12 // globals 13 int th_counter[N]; 14 int counter; 15 16 17 // Compiler-generated code (emulation) 18 typedef struct ident { 19 void* dummy; 20 } ident_t; 21 22 typedef struct shar { 23 int(*pth_counter)[N]; 24 int *pcounter; 25 int *pj; 26 } *pshareds; 27 28 typedef struct task { 29 pshareds shareds; 30 int(* routine)(int,struct task*); 31 int part_id; 32 // privates: 33 unsigned long long lb; // library always uses ULONG 34 unsigned long long ub; 35 int st; 36 int last; 37 int i; 38 int j; 39 int th; 40 } *ptask, kmp_task_t; 41 42 typedef int(* task_entry_t)( int, ptask ); 43 44 void 45 __task_dup_entry(ptask task_dst, ptask task_src, int lastpriv) 46 { 47 // setup lastprivate flag 48 task_dst->last = lastpriv; 49 // could be constructor calls here... 50 } 51 52 53 // OpenMP RTL interfaces 54 typedef unsigned long long kmp_uint64; 55 typedef long long kmp_int64; 56 57 #ifdef __cplusplus 58 extern "C" { 59 #endif 60 void 61 __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, 62 kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, 63 int nogroup, int sched, kmp_int64 grainsize, void *task_dup ); 64 ptask 65 __kmpc_omp_task_alloc( ident_t *loc, int gtid, int flags, 66 size_t sizeof_kmp_task_t, size_t sizeof_shareds, 67 task_entry_t task_entry ); 68 void __kmpc_atomic_fixed4_add(void *id_ref, int gtid, int * lhs, int rhs); 69 int __kmpc_global_thread_num(void *id_ref); 70 #ifdef __cplusplus 71 } 72 #endif 73 74 75 // User's code 76 int task_entry(int gtid, ptask task) 77 { 78 pshareds pshar = task->shareds; 79 for( task->i = task->lb; task->i <= (int)task->ub; task->i += task->st ) { 80 task->th = omp_get_thread_num(); 81 __kmpc_atomic_fixed4_add(NULL,gtid,pshar->pcounter,1); 82 __kmpc_atomic_fixed4_add(NULL,gtid,&((*pshar->pth_counter)[task->th]),1); 83 task->j = task->i; 84 } 85 my_sleep( 0.1 ); // sleep 100 ms in order to allow other threads to steal tasks 86 if( task->last ) { 87 *(pshar->pj) = task->j; // lastprivate 88 } 89 return 0; 90 } 91 92 int main() 93 { 94 int i, j, gtid = __kmpc_global_thread_num(NULL); 95 ptask task; 96 pshareds psh; 97 omp_set_dynamic(0); 98 counter = 0; 99 for( i=0; i<N; ++i ) 100 th_counter[i] = 0; 101 #pragma omp parallel num_threads(N) 102 { 103 #pragma omp master 104 { 105 int gtid = __kmpc_global_thread_num(NULL); 106 /* 107 * This is what the OpenMP runtime calls correspond to: 108 #pragma omp taskloop num_tasks(N) lastprivate(j) 109 for( i=0; i<N*GRAIN*STRIDE-1; i+=STRIDE ) 110 { 111 int th = omp_get_thread_num(); 112 #pragma omp atomic 113 counter++; 114 #pragma omp atomic 115 th_counter[th]++; 116 j = i; 117 } 118 */ 119 task = __kmpc_omp_task_alloc(NULL,gtid,1,sizeof(struct task),sizeof(struct shar),&task_entry); 120 psh = task->shareds; 121 psh->pth_counter = &th_counter; 122 psh->pcounter = &counter; 123 psh->pj = &j; 124 task->lb = 0; 125 task->ub = N*GRAIN*STRIDE-2; 126 task->st = STRIDE; 127 128 __kmpc_taskloop( 129 NULL, // location 130 gtid, // gtid 131 task, // task structure 132 1, // if clause value 133 &task->lb, // lower bound 134 &task->ub, // upper bound 135 STRIDE, // loop increment 136 0, // 1 if nogroup specified 137 2, // schedule type: 0-none, 1-grainsize, 2-num_tasks 138 N, // schedule value (ignored for type 0) 139 (void*)&__task_dup_entry // tasks duplication routine 140 ); 141 } // end master 142 } // end parallel 143 // check results 144 if( j != N*GRAIN*STRIDE-STRIDE ) { 145 printf("Error in lastprivate, %d != %d\n",j,N*GRAIN*STRIDE-STRIDE); 146 return 1; 147 } 148 if( counter != N*GRAIN ) { 149 printf("Error, counter %d != %d\n",counter,N*GRAIN); 150 return 1; 151 } 152 for( i=0; i<N; ++i ) { 153 if( th_counter[i] % GRAIN ) { 154 printf("Error, th_counter[%d] = %d\n",i,th_counter[i]); 155 return 1; 156 } 157 } 158 printf("passed\n"); 159 return 0; 160 } 161