377 lines · cpp
1// RUN: %libomp-cxx-compile-and-run2// RUN: %libomp-cxx-compile -DFLG=1 && %libomp-run3// GCC-5 is needed for OpenMP 4.0 support (taskgroup)4// XFAIL: gcc-45#include <cstdio>6#include <cmath>7#include <cassert>8#include <omp.h>9 10// Total number of loop iterations, should be multiple of T for this test11#define N 1000012 13// Flag to request lazy (1) or eager (0) allocation of reduction objects14#ifndef FLG15#define FLG 016#endif17 18/*19 // initial user's code that corresponds to pseudo code of the test20 #pragma omp taskgroup task_reduction(+:i,j) task_reduction(*:x)21 {22 for( int l = 0; l < N; ++l ) {23 #pragma omp task firstprivate(l) in_reduction(+:i) in_reduction(*:x)24 {25 i += l;26 if( l%2 )27 x *= 1.0 / (l + 1);28 else29 x *= (l + 1);30 }31 }32 33 #pragma omp taskgroup task_reduction(-:i,k) task_reduction(+:y)34 {35 for( int l = 0; l < N; ++l ) {36 #pragma omp task firstprivate(l) in_reduction(+:j,y) \37 in_reduction(*:x) in_reduction(-:k)38 {39 j += l;40 k -= l;41 y += (double)l;42 if( l%2 )43 x *= 1.0 / (l + 1);44 else45 x *= (l + 1);46 }47 #pragma omp task firstprivate(l) in_reduction(+:y) in_reduction(-:i,k)48 {49 i -= l;50 k -= l;51 y += (double)l;52 }53 #pragma omp task firstprivate(l) in_reduction(+:j) in_reduction(*:x)54 {55 j += l;56 if( l%2 )57 x *= 1.0 / (l + 1);58 else59 x *= (l + 1);60 }61 }62 } // inner reduction63 64 for( int l = 0; l < N; ++l ) {65 #pragma omp task firstprivate(l) in_reduction(+:j)66 j += l;67 }68 } // outer reduction69*/70 71//------------------------------------------------72// OpenMP runtime library routines73#ifdef __cplusplus74extern "C" {75#endif76extern void* __kmpc_task_reduction_get_th_data(int gtid, void* tg, void* item);77extern void* __kmpc_task_reduction_init(int gtid, int num, void* data);78extern int __kmpc_global_thread_num(void*);79#ifdef __cplusplus80}81#endif82 83//------------------------------------------------84// Compiler-generated code85 86typedef struct _task_red_item {87 void *shar; // shared reduction item88 size_t size; // size of data item89 void *f_init; // data initialization routine90 void *f_fini; // data finalization routine91 void *f_comb; // data combiner routine92 unsigned flags;93} _task_red_item_t;94 95// int:+ no need in init/fini callbacks, valid for subtraction96void __red_int_add_comb(void *lhs, void *rhs) // combiner97{ *(int*)lhs += *(int*)rhs; }98 99// long long:+ no need in init/fini callbacks, valid for subtraction100void __red_llong_add_comb(void *lhs, void *rhs) // combiner101{ *(long long*)lhs += *(long long*)rhs; }102 103// double:* no need in fini callback104void __red_dbl_mul_init(void *data) // initializer105{ *(double*)data = 1.0; }106void __red_dbl_mul_comb(void *lhs, void *rhs) // combiner107{ *(double*)lhs *= *(double*)rhs; }108 109// double:+ no need in init/fini callbacks110void __red_dbl_add_comb(void *lhs, void *rhs) // combiner111{ *(double*)lhs += *(double*)rhs; }112 113// ==============================114 115void calc_serial(int *pi, long long *pj, double *px, long long *pk, double *py)116{117 for( int l = 0; l < N; ++l ) {118 *pi += l;119 if( l%2 )120 *px *= 1.0 / (l + 1);121 else122 *px *= (l + 1);123 }124 for( int l = 0; l < N; ++l ) {125 *pj += l;126 *pk -= l;127 *py += (double)l;128 if( l%2 )129 *px *= 1.0 / (l + 1);130 else131 *px *= (l + 1);132 133 *pi -= l;134 *pk -= l;135 *py += (double)l;136 137 *pj += l;138 if( l%2 )139 *px *= 1.0 / (l + 1);140 else141 *px *= (l + 1);142 }143 for( int l = 0; l < N; ++l ) {144 *pj += l;145 }146}147 148//------------------------------------------------149// Test case150int main()151{152 int nthreads = omp_get_max_threads();153 int err = 0;154 void** ptrs = (void**)malloc(nthreads*sizeof(void*));155 156 // user's code ======================================157 // variables for serial calculations:158 int is = 3;159 long long js = -9999999;160 double xs = 99999.0;161 long long ks = 99999999;162 double ys = -99999999.0;163 // variables for parallel calculations:164 int ip = 3;165 long long jp = -9999999;166 double xp = 99999.0;167 long long kp = 99999999;168 double yp = -99999999.0;169 170 calc_serial(&is, &js, &xs, &ks, &ys);171 // ==================================================172 for (int i = 0; i < nthreads; ++i)173 ptrs[i] = NULL;174 #pragma omp parallel175 {176 #pragma omp single nowait177 {178 // outer taskgroup reduces (i,j,x)179 #pragma omp taskgroup // task_reduction(+:i,j) task_reduction(*:x)180 {181 _task_red_item_t red_data[3];182 red_data[0].shar = &ip;183 red_data[0].size = sizeof(ip);184 red_data[0].f_init = NULL; // RTL will zero thread-specific objects185 red_data[0].f_fini = NULL; // no destructors needed186 red_data[0].f_comb = (void*)&__red_int_add_comb;187 red_data[0].flags = FLG;188 red_data[1].shar = &jp;189 red_data[1].size = sizeof(jp);190 red_data[1].f_init = NULL; // RTL will zero thread-specific objects191 red_data[1].f_fini = NULL; // no destructors needed192 red_data[1].f_comb = (void*)&__red_llong_add_comb;193 red_data[1].flags = FLG;194 red_data[2].shar = &xp;195 red_data[2].size = sizeof(xp);196 red_data[2].f_init = (void*)&__red_dbl_mul_init;197 red_data[2].f_fini = NULL; // no destructors needed198 red_data[2].f_comb = (void*)&__red_dbl_mul_comb;199 red_data[2].flags = FLG;200 int gtid = __kmpc_global_thread_num(NULL);201 void* tg1 = __kmpc_task_reduction_init(gtid, 3, red_data);202 203 for( int l = 0; l < N; l += 2 ) {204 // 2 iterations per task to get correct x value; actually any even205 // number of iters per task will work, otherwise x looses precision206 #pragma omp task firstprivate(l) //in_reduction(+:i) in_reduction(*:x)207 {208 int gtid = __kmpc_global_thread_num(NULL);209 int *p_ip = (int*)__kmpc_task_reduction_get_th_data(gtid, tg1, &ip);210 double *p_xp = (double*)__kmpc_task_reduction_get_th_data(211 gtid, tg1, &xp);212 if (!ptrs[gtid]) ptrs[gtid] = p_xp;213 214 // user's pseudo-code ==============================215 *p_ip += l;216 *p_xp *= (l + 1);217 218 *p_ip += l + 1;219 *p_xp *= 1.0 / (l + 2);220 // ==================================================221 }222 }223 // inner taskgroup reduces (i,k,y), i is same object as in outer one224 #pragma omp taskgroup // task_reduction(-:i,k) task_reduction(+:y)225 {226 _task_red_item_t red_data[3];227 red_data[0].shar = &ip;228 red_data[0].size = sizeof(ip);229 red_data[0].f_init = NULL; // RTL will zero thread-specific objects230 red_data[0].f_fini = NULL; // no destructors needed231 red_data[0].f_comb = (void*)&__red_int_add_comb;232 red_data[0].flags = FLG;233 red_data[1].shar = &kp;234 red_data[1].size = sizeof(kp);235 red_data[1].f_init = NULL; // RTL will zero thread-specific objects236 red_data[1].f_fini = NULL; // no destructors needed237 red_data[1].f_comb = (void*)&__red_llong_add_comb; // same for + and -238 red_data[1].flags = FLG;239 red_data[2].shar = &yp;240 red_data[2].size = sizeof(yp);241 red_data[2].f_init = NULL; // RTL will zero thread-specific objects242 red_data[2].f_fini = NULL; // no destructors needed243 red_data[2].f_comb = (void*)&__red_dbl_add_comb;244 red_data[2].flags = FLG;245 int gtid = __kmpc_global_thread_num(NULL);246 void* tg2 = __kmpc_task_reduction_init(gtid, 3, red_data);247 248 for( int l = 0; l < N; l += 2 ) {249 #pragma omp task firstprivate(l)250 // in_reduction(+:j,y) in_reduction(*:x) in_reduction(-:k)251 {252 int gtid = __kmpc_global_thread_num(NULL);253 long long *p_jp = (long long*)__kmpc_task_reduction_get_th_data(254 gtid, tg1, &jp);255 long long *p_kp = (long long*)__kmpc_task_reduction_get_th_data(256 gtid, tg2, &kp);257 double *p_xp = (double*)__kmpc_task_reduction_get_th_data(258 gtid, tg1, &xp);259 double *p_yp = (double*)__kmpc_task_reduction_get_th_data(260 gtid, tg2, &yp);261 // user's pseudo-code ==============================262 *p_jp += l;263 *p_kp -= l;264 *p_yp += (double)l;265 *p_xp *= (l + 1);266 267 *p_jp += l + 1;268 *p_kp -= l + 1;269 *p_yp += (double)(l + 1);270 *p_xp *= 1.0 / (l + 2);271 // =================================================272{273 // the following code is here just to check __kmpc_task_reduction_get_th_data:274 int tid = omp_get_thread_num();275 void *addr1;276 void *addr2;277 addr1 = __kmpc_task_reduction_get_th_data(gtid, tg1, &xp); // from shared278 addr2 = __kmpc_task_reduction_get_th_data(gtid, tg1, addr1); // from private279 if (addr1 != addr2) {280 #pragma omp atomic281 ++err;282 printf("Wrong thread-specific addresses %d s:%p p:%p\n", tid, addr1, addr2);283 }284 // from neighbour w/o taskgroup (should start lookup from current tg2)285 if (tid > 0) {286 if (ptrs[tid-1]) {287 addr2 = __kmpc_task_reduction_get_th_data(gtid, NULL, ptrs[tid-1]);288 if (addr1 != addr2) {289 #pragma omp atomic290 ++err;291 printf("Wrong thread-specific addresses %d s:%p n:%p\n",292 tid, addr1, addr2);293 }294 }295 } else {296 if (ptrs[nthreads-1]) {297 addr2 = __kmpc_task_reduction_get_th_data(gtid, NULL, ptrs[nthreads-1]);298 if (addr1 != addr2) {299 #pragma omp atomic300 ++err;301 printf("Wrong thread-specific addresses %d s:%p n:%p\n",302 tid, addr1, addr2);303 }304 }305 }306 // ----------------------------------------------307}308 }309 #pragma omp task firstprivate(l)310 // in_reduction(+:y) in_reduction(-:i,k)311 {312 int gtid = __kmpc_global_thread_num(NULL);313 int *p_ip = (int*)__kmpc_task_reduction_get_th_data(314 gtid, tg2, &ip);315 long long *p_kp = (long long*)__kmpc_task_reduction_get_th_data(316 gtid, tg2, &kp);317 double *p_yp = (double*)__kmpc_task_reduction_get_th_data(318 gtid, tg2, &yp);319 320 // user's pseudo-code ==============================321 *p_ip -= l;322 *p_kp -= l;323 *p_yp += (double)l;324 325 *p_ip -= l + 1;326 *p_kp -= l + 1;327 *p_yp += (double)(l + 1);328 // =================================================329 }330 #pragma omp task firstprivate(l)331 // in_reduction(+:j) in_reduction(*:x)332 {333 int gtid = __kmpc_global_thread_num(NULL);334 long long *p_jp = (long long*)__kmpc_task_reduction_get_th_data(335 gtid, tg1, &jp);336 double *p_xp = (double*)__kmpc_task_reduction_get_th_data(337 gtid, tg1, &xp);338 // user's pseudo-code ==============================339 *p_jp += l;340 *p_xp *= (l + 1);341 342 *p_jp += l + 1;343 *p_xp *= 1.0 / (l + 2);344 // =================================================345 }346 }347 } // inner reduction348 349 for( int l = 0; l < N; l += 2 ) {350 #pragma omp task firstprivate(l) // in_reduction(+:j)351 {352 int gtid = __kmpc_global_thread_num(NULL);353 long long *p_jp = (long long*)__kmpc_task_reduction_get_th_data(354 gtid, tg1, &jp);355 // user's pseudo-code ==============================356 *p_jp += l;357 *p_jp += l + 1;358 // =================================================359 }360 }361 } // outer reduction362 } // end single363 } // end parallel364 // check results365#if _DEBUG366 printf("reduction flags = %u\n", FLG);367#endif368 if (ip == is && jp == js && ks == kp &&369 fabs(xp - xs) < 0.01 && fabs(yp - ys) < 0.01)370 printf("passed\n");371 else372 printf("failed,\n ser:(%d %lld %f %lld %f)\n par:(%d %lld %f %lld %f)\n",373 is, js, xs, ks, ys,374 ip, jp, xp, kp, yp);375 return 0;376}377