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