160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
| // 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;
 | |
| }
 |