| // 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; | |
| } |