| // RUN: %libomp-compile-and-run |
| // RUN: %libomp-compile && env KMP_TASKLOOP_MIN_TASKS=1 %libomp-run |
| #include <stdio.h> |
| #include <omp.h> |
| #include "omp_my_sleep.h" |
| |
| #define N 4 |
| #define GRAIN 10 |
| #define STRIDE 3 |
| |
| // globals |
| int th_counter[N]; |
| int counter; |
| |
| |
| // Compiler-generated code (emulation) |
| typedef struct ident { |
| void* dummy; |
| } ident_t; |
| |
| typedef struct shar { |
| int(*pth_counter)[N]; |
| int *pcounter; |
| int *pj; |
| } *pshareds; |
| |
| typedef struct task { |
| pshareds shareds; |
| int(* routine)(int,struct task*); |
| int part_id; |
| // privates: |
| unsigned long long lb; // library always uses ULONG |
| unsigned long long ub; |
| int st; |
| int last; |
| int i; |
| int j; |
| int th; |
| } *ptask, kmp_task_t; |
| |
| typedef int(* task_entry_t)( int, ptask ); |
| |
| void |
| __task_dup_entry(ptask task_dst, ptask task_src, int lastpriv) |
| { |
| // setup lastprivate flag |
| task_dst->last = lastpriv; |
| // could be constructor calls here... |
| } |
| |
| |
| // OpenMP RTL interfaces |
| typedef unsigned long long kmp_uint64; |
| typedef long long kmp_int64; |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| void |
| __kmpc_taskloop(ident_t *loc, int gtid, kmp_task_t *task, int if_val, |
| kmp_uint64 *lb, kmp_uint64 *ub, kmp_int64 st, |
| int nogroup, int sched, kmp_int64 grainsize, void *task_dup ); |
| ptask |
| __kmpc_omp_task_alloc( ident_t *loc, int gtid, int flags, |
| size_t sizeof_kmp_task_t, size_t sizeof_shareds, |
| task_entry_t task_entry ); |
| void __kmpc_atomic_fixed4_add(void *id_ref, int gtid, int * lhs, int rhs); |
| int __kmpc_global_thread_num(void *id_ref); |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| |
| // User's code |
| int task_entry(int gtid, ptask task) |
| { |
| pshareds pshar = task->shareds; |
| for( task->i = task->lb; task->i <= (int)task->ub; task->i += task->st ) { |
| task->th = omp_get_thread_num(); |
| __kmpc_atomic_fixed4_add(NULL,gtid,pshar->pcounter,1); |
| __kmpc_atomic_fixed4_add(NULL,gtid,&((*pshar->pth_counter)[task->th]),1); |
| task->j = task->i; |
| } |
| my_sleep( 0.1 ); // sleep 100 ms in order to allow other threads to steal tasks |
| if( task->last ) { |
| *(pshar->pj) = task->j; // lastprivate |
| } |
| return 0; |
| } |
| |
| int main() |
| { |
| int i, j, gtid = __kmpc_global_thread_num(NULL); |
| ptask task; |
| pshareds psh; |
| omp_set_dynamic(0); |
| counter = 0; |
| for( i=0; i<N; ++i ) |
| th_counter[i] = 0; |
| #pragma omp parallel num_threads(N) |
| { |
| #pragma omp master |
| { |
| int gtid = __kmpc_global_thread_num(NULL); |
| /* |
| * This is what the OpenMP runtime calls correspond to: |
| #pragma omp taskloop num_tasks(N) lastprivate(j) |
| for( i=0; i<N*GRAIN*STRIDE-1; i+=STRIDE ) |
| { |
| int th = omp_get_thread_num(); |
| #pragma omp atomic |
| counter++; |
| #pragma omp atomic |
| th_counter[th]++; |
| j = i; |
| } |
| */ |
| task = __kmpc_omp_task_alloc(NULL,gtid,1,sizeof(struct task),sizeof(struct shar),&task_entry); |
| psh = task->shareds; |
| psh->pth_counter = &th_counter; |
| psh->pcounter = &counter; |
| psh->pj = &j; |
| task->lb = 0; |
| task->ub = N*GRAIN*STRIDE-2; |
| task->st = STRIDE; |
| |
| __kmpc_taskloop( |
| NULL, // location |
| gtid, // gtid |
| task, // task structure |
| 1, // if clause value |
| &task->lb, // lower bound |
| &task->ub, // upper bound |
| STRIDE, // loop increment |
| 0, // 1 if nogroup specified |
| 2, // schedule type: 0-none, 1-grainsize, 2-num_tasks |
| N, // schedule value (ignored for type 0) |
| (void*)&__task_dup_entry // tasks duplication routine |
| ); |
| } // end master |
| } // end parallel |
| // check results |
| if( j != N*GRAIN*STRIDE-STRIDE ) { |
| printf("Error in lastprivate, %d != %d\n",j,N*GRAIN*STRIDE-STRIDE); |
| return 1; |
| } |
| if( counter != N*GRAIN ) { |
| printf("Error, counter %d != %d\n",counter,N*GRAIN); |
| return 1; |
| } |
| for( i=0; i<N; ++i ) { |
| if( th_counter[i] % GRAIN ) { |
| printf("Error, th_counter[%d] = %d\n",i,th_counter[i]); |
| return 1; |
| } |
| } |
| printf("passed\n"); |
| return 0; |
| } |