160 lines · c
1// RUN: %libomp-compile-and-run2// RUN: %libomp-compile && env KMP_TASKLOOP_MIN_TASKS=1 %libomp-run3#include <stdio.h>4#include <omp.h>5#include "omp_my_sleep.h"6 7#define N 48#define GRAIN 109#define STRIDE 310 11// globals12int th_counter[N];13int counter;14 15 16// Compiler-generated code (emulation)17typedef struct ident {18 void* dummy;19} ident_t;20 21typedef struct shar {22 int(*pth_counter)[N];23 int *pcounter;24 int *pj;25} *pshareds;26 27typedef 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 ULONG33 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 41typedef int(* task_entry_t)( int, ptask );42 43void44__task_dup_entry(ptask task_dst, ptask task_src, int lastpriv)45{46// setup lastprivate flag47 task_dst->last = lastpriv;48// could be constructor calls here...49}50 51 52// OpenMP RTL interfaces53typedef unsigned long long kmp_uint64;54typedef long long kmp_int64;55 56#ifdef __cplusplus57extern "C" {58#endif59void60__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 );63ptask64__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 );67void __kmpc_atomic_fixed4_add(void *id_ref, int gtid, int * lhs, int rhs);68int __kmpc_global_thread_num(void *id_ref);69#ifdef __cplusplus70}71#endif72 73 74// User's code75int 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 tasks85 if( task->last ) {86 *(pshar->pj) = task->j; // lastprivate87 }88 return 0;89}90 91int 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 master103 {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 atomic112 counter++;113 #pragma omp atomic114 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, // location129 gtid, // gtid130 task, // task structure131 1, // if clause value132 &task->lb, // lower bound133 &task->ub, // upper bound134 STRIDE, // loop increment135 0, // 1 if nogroup specified136 2, // schedule type: 0-none, 1-grainsize, 2-num_tasks137 N, // schedule value (ignored for type 0)138 (void*)&__task_dup_entry // tasks duplication routine139 );140 } // end master141 } // end parallel142// check results143 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