| 1 | // RUN: %libomp-compile-and-run |
| 2 | |
| 3 | // The test checks OMP 5.0 monotonic/nonmonotonic scheduling API |
| 4 | // 1. initial schedule should be (static,0) |
| 5 | // 2. omp_get_schedule() should return the schedule set by omp_set_schedule() |
| 6 | // 3. schedules set inside parallel should not impact outer tasks' schedules |
| 7 | |
| 8 | #include <stdio.h> |
| 9 | #ifndef __INTEL_COMPILER |
| 10 | #define _OMPIMP |
| 11 | #endif |
| 12 | |
| 13 | #define NO_MODIFIERS ((omp_sched_t)0) |
| 14 | |
| 15 | #include "omp.h" |
| 16 | |
| 17 | int global = 0; |
| 18 | int err = 0; |
| 19 | |
| 20 | omp_sched_t sched_append_modifiers(omp_sched_t sched, omp_sched_t modifiers) { |
| 21 | return (omp_sched_t)((int)sched | (int)modifiers); |
| 22 | } |
| 23 | |
| 24 | omp_sched_t sched_without_modifiers(omp_sched_t sched) { |
| 25 | return (omp_sched_t)((int)sched & ~((int)omp_sched_monotonic)); |
| 26 | } |
| 27 | |
| 28 | int sched_has_modifiers(omp_sched_t sched, omp_sched_t modifiers) { |
| 29 | return (((int)sched & ((int)omp_sched_monotonic)) > 0); |
| 30 | } |
| 31 | |
| 32 | // check that sched = hope | modifiers |
| 33 | void check_schedule(const char *, const omp_sched_t sched, int chunk, |
| 34 | omp_sched_t hope_sched, int hope_chunk) { |
| 35 | |
| 36 | if (sched != hope_sched || chunk != hope_chunk) { |
| 37 | #pragma omp atomic |
| 38 | ++err; |
| 39 | printf(format: "Error: %s: schedule: (%d, %d) is not equal to (%d, %d)\n" , extra, |
| 40 | (int)hope_sched, hope_chunk, (int)sched, chunk); |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | int main() { |
| 45 | int i; |
| 46 | int chunk; |
| 47 | omp_sched_t sched0; |
| 48 | |
| 49 | omp_set_dynamic(0); |
| 50 | omp_set_nested(1); |
| 51 | |
| 52 | // check serial region |
| 53 | omp_get_schedule(&sched0, &chunk); |
| 54 | #ifdef DEBUG |
| 55 | printf("initial: (%d, %d)\n" , sched0, chunk); |
| 56 | #endif |
| 57 | check_schedule(extra: "initial" , sched: omp_sched_static, chunk: 0, hope_sched: sched0, hope_chunk: chunk); |
| 58 | // set schedule before the parallel, check it after the parallel |
| 59 | omp_set_schedule( |
| 60 | sched_append_modifiers(sched: omp_sched_dynamic, modifiers: omp_sched_monotonic), 3); |
| 61 | |
| 62 | #pragma omp parallel num_threads(3) private(i) |
| 63 | { |
| 64 | omp_sched_t n_outer_set, n_outer_get; |
| 65 | int c_outer; |
| 66 | int tid = omp_get_thread_num(); |
| 67 | |
| 68 | n_outer_set = sched_append_modifiers(sched: (omp_sched_t)(tid + 1), |
| 69 | modifiers: omp_sched_monotonic); // 1, 2, 3 |
| 70 | |
| 71 | // check outer parallel region |
| 72 | // master sets (static, unchunked), others - (dynamic, 1), (guided, 2) |
| 73 | // set schedule before inner parallel, check it after the parallel |
| 74 | omp_set_schedule(n_outer_set, tid); |
| 75 | |
| 76 | // Make sure this schedule doesn't crash the runtime |
| 77 | #pragma omp for |
| 78 | for (i = 0; i < 100; ++i) { |
| 79 | #pragma omp atomic |
| 80 | global++; |
| 81 | } |
| 82 | |
| 83 | #pragma omp parallel num_threads(3) private(i) shared(n_outer_set) |
| 84 | { |
| 85 | omp_sched_t n_inner_set, n_inner_get; |
| 86 | int c_inner_set, c_inner_get; |
| 87 | int tid = omp_get_thread_num(); |
| 88 | |
| 89 | n_inner_set = (omp_sched_t)(tid + 1); // 1, 2, 3 |
| 90 | c_inner_set = (int)(n_outer_set)*10 + |
| 91 | (int)n_inner_set; // 11, 12, 13, 21, 22, 23, 31, 32, 33 |
| 92 | n_inner_set = sched_append_modifiers(sched: n_inner_set, modifiers: omp_sched_monotonic); |
| 93 | // schedules set inside parallel should not impact outer schedules |
| 94 | omp_set_schedule(n_inner_set, c_inner_set); |
| 95 | |
| 96 | // Make sure this schedule doesn't crash the runtime |
| 97 | #pragma omp for |
| 98 | for (i = 0; i < 100; ++i) { |
| 99 | #pragma omp atomic |
| 100 | global++; |
| 101 | } |
| 102 | |
| 103 | #pragma omp barrier |
| 104 | omp_get_schedule(&n_inner_get, &c_inner_get); |
| 105 | #ifdef DEBUG |
| 106 | printf("inner parallel: o_th %d, i_th %d, (%d, %d)\n" , n_outer_set - 1, |
| 107 | tid, n_inner_get, c_inner_get); |
| 108 | #endif |
| 109 | check_schedule(extra: "inner" , sched: n_inner_set, chunk: c_inner_set, hope_sched: n_inner_get, |
| 110 | hope_chunk: c_inner_get); |
| 111 | } |
| 112 | |
| 113 | omp_get_schedule(&n_outer_get, &c_outer); |
| 114 | #ifdef DEBUG |
| 115 | printf("outer parallel: thread %d, (%d, %d)\n" , tid, n_outer_get, c_outer); |
| 116 | #endif |
| 117 | check_schedule(extra: "outer" , sched: n_outer_set, chunk: tid, hope_sched: n_outer_get, hope_chunk: c_outer); |
| 118 | } |
| 119 | |
| 120 | omp_get_schedule(&sched0, &chunk); |
| 121 | #ifdef DEBUG |
| 122 | printf("after parallels: (%d, %d)\n" , sched0, chunk); |
| 123 | #endif |
| 124 | check_schedule(extra: "after parallels" , |
| 125 | sched: sched_append_modifiers(sched: omp_sched_dynamic, modifiers: omp_sched_monotonic), |
| 126 | chunk: 3, hope_sched: sched0, hope_chunk: chunk); |
| 127 | |
| 128 | if (err > 0) { |
| 129 | printf(format: "Failed\n" ); |
| 130 | return 1; |
| 131 | } |
| 132 | printf(format: "Passed\n" ); |
| 133 | return 0; |
| 134 | } |
| 135 | |