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 | |