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,lhs: pshar->pcounter,rhs: 1); |
81 | __kmpc_atomic_fixed4_add(NULL,gtid,lhs: &((*pshar->pth_counter)[task->th]),rhs: 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,flags: 1,sizeof_kmp_task_t: sizeof(struct task),sizeof_shareds: sizeof(struct shar),task_entry: &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 | if_val: 1, // if clause value |
132 | lb: &task->lb, // lower bound |
133 | ub: &task->ub, // upper bound |
134 | STRIDE, // loop increment |
135 | nogroup: 0, // 1 if nogroup specified |
136 | sched: 2, // schedule type: 0-none, 1-grainsize, 2-num_tasks |
137 | N, // schedule value (ignored for type 0) |
138 | task_dup: (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(format: "Error in lastprivate, %d != %d\n" ,j,N*GRAIN*STRIDE-STRIDE); |
145 | return 1; |
146 | } |
147 | if( counter != N*GRAIN ) { |
148 | printf(format: "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(format: "Error, th_counter[%d] = %d\n" ,i,th_counter[i]); |
154 | return 1; |
155 | } |
156 | } |
157 | printf(format: "passed\n" ); |
158 | return 0; |
159 | } |
160 | |