1 /*
2  * Copyright (C) by Argonne National Laboratory
3  *     See COPYRIGHT in top-level directory
4  */
5 
6 /* This test checks accumulate ordering in three cases:
7  * 1) Default (most restricted)
8  * 2) None (no ordering)
9  * 3) Mixture of REPLACE and MIN_LOC/MAX_LOC.
10  *    (In CH4/OFI, REPLACE may go through OFI but MIN_LOC/MAX_LOC has to go through active message.)
11  */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <mpi.h>
16 #include <limits.h>
17 #include "mpitest.h"
18 
19 typedef struct {
20     int val;
21     int loc;
22 } twoint_t;
23 
24 #define ARRAY_LEN (8192/(sizeof(twoint_t)))
25 
26 static int errs = 0;
27 
verify_result(twoint_t * data,int len,twoint_t expected,const char * test_name)28 void verify_result(twoint_t * data, int len, twoint_t expected, const char *test_name)
29 {
30     int i;
31     for (i = 0; i < len; i++) {
32         if ((data[i].val != expected.val) || (data[i].loc != expected.loc)) {
33             errs++;
34             printf("%s: Expected: { loc = %d, val = %d }  Actual: { loc = %d, val = %d }\n",
35                    test_name, expected.loc, expected.val, data[i].loc, data[i].val);
36         }
37     }
38 }
39 
40 /* Check non-deterministic result of none ordering.
41  * Expected result has two possibilities. */
verify_nondeterministic_result(twoint_t * data,int len,twoint_t * expected,const char * test_name)42 void verify_nondeterministic_result(twoint_t * data,
43                                     int len, twoint_t * expected, const char *test_name)
44 {
45     int i;
46     for (i = 0; i < len; i++) {
47         if (!((data[i].loc == expected[0].loc && data[0].val == expected[0].val)
48               || (data[i].loc == expected[1].loc && data[i].val == expected[1].val))) {
49             errs++;
50             printf
51                 ("%s: Expected: { loc = %d, val = %d } or { loc = %d, val = %d }; Actual: { loc = %d, val = %d }\n",
52                  test_name, expected[0].loc, expected[0].val, expected[1].loc, expected[1].val,
53                  data[i].loc, data[i].val);
54         }
55     }
56 }
57 
main(int argc,char ** argv)58 int main(int argc, char **argv)
59 {
60     int me, nproc, i;
61     twoint_t *data, *mine, *mine_plus, *expected;
62     MPI_Win win;
63     MPI_Info info_in;
64 
65     MTest_Init(&argc, &argv);
66 
67     MPI_Comm_rank(MPI_COMM_WORLD, &me);
68     MPI_Comm_size(MPI_COMM_WORLD, &nproc);
69 
70     if (nproc < 2) {
71         printf("Run this program with 2 or more processes\n");
72         MPI_Abort(MPI_COMM_WORLD, 1);
73     }
74 
75     data = (twoint_t *) calloc(ARRAY_LEN, sizeof(twoint_t));
76     if (me == 0) {
77         /* length of 2 in order to store all results for none ordering. */
78         expected = (twoint_t *) malloc(2 * sizeof(twoint_t));
79     }
80     if (me == nproc - 1) {
81         mine = (twoint_t *) malloc(ARRAY_LEN * sizeof(twoint_t));
82         mine_plus = (twoint_t *) malloc(ARRAY_LEN * sizeof(twoint_t));
83         for (i = 0; i < ARRAY_LEN; i++) {
84             mine[i].val = me + 1;
85             mine[i].loc = me;
86             mine_plus[i].val = me + 2;
87             mine_plus[i].loc = me + 1;
88         }
89     }
90 
91     /* 1. Default ordering */
92     MPI_Win_create(data, sizeof(twoint_t) * ARRAY_LEN, 1, MPI_INFO_NULL, MPI_COMM_WORLD, &win);
93     MPI_Win_fence(0, win);
94 
95     /* Rank np-1 performs 2 WRITE to rank 0. */
96     /* 1.a. Single data test */
97     if (me == nproc - 1) {
98         MPI_Accumulate(mine, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_REPLACE, win);
99         MPI_Accumulate(mine_plus, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_REPLACE, win);
100     }
101 
102     MPI_Win_fence(0, win);
103     if (me == 0) {
104         expected[0].loc = nproc;
105         expected[0].val = nproc + 1;
106         verify_result(data, 1, expected[0], "Single data test case for default ordering");
107     }
108 
109     if (me == 0) {
110         data[0].loc = 0;
111         data[0].val = 0;
112     }
113     MPI_Win_fence(0, win);
114     /* 1.b. Large arrary test */
115     if (me == nproc - 1) {
116         MPI_Accumulate(mine, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_REPLACE, win);
117         MPI_Accumulate(mine_plus, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_REPLACE, win);
118     }
119 
120     MPI_Win_fence(0, win);
121     if (me == 0) {
122         verify_result(data, ARRAY_LEN, expected[0], "Large array test case for default ordering");
123     }
124     /* MPI Implementation may ignore window info changes once created.
125      * Thus we should free current window and create a new window with required info. */
126     MPI_Win_free(&win);
127 
128     /* 2. None ordering */
129     if (me == 0) {
130         /* reset data on rank 0. */
131         memset((void *) data, 0, ARRAY_LEN * sizeof(twoint_t));
132     }
133 
134     MPI_Info_create(&info_in);
135     MPI_Info_set(info_in, "accumulate_ordering", "none");
136     MPI_Win_create(data, sizeof(twoint_t) * ARRAY_LEN, 1, info_in, MPI_COMM_WORLD, &win);
137     MPI_Info_free(&info_in);
138 
139     MPI_Win_fence(0, win);
140 
141     /* Rank np-1 performs 2 WRITE to rank 0. */
142     /* 2.a. Single data test */
143     if (me == nproc - 1) {
144         MPI_Accumulate(mine, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_REPLACE, win);
145         MPI_Accumulate(mine_plus, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_REPLACE, win);
146     }
147 
148     MPI_Win_fence(0, win);
149     if (me == 0) {
150         expected[0].loc = nproc - 1;
151         expected[0].val = nproc;
152         expected[1].loc = nproc;
153         expected[1].val = nproc + 1;
154         verify_nondeterministic_result(data, 1, expected,
155                                        "Single data test case for none ordering");
156     }
157 
158     if (me == 0) {
159         data[0].loc = 0;
160         data[0].val = 0;
161     }
162     MPI_Win_fence(0, win);
163     /* 2.b. Large array test */
164     if (me == nproc - 1) {
165         MPI_Accumulate(mine, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_REPLACE, win);
166         MPI_Accumulate(mine_plus, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_REPLACE, win);
167     }
168 
169     MPI_Win_fence(0, win);
170     if (me == 0) {
171         verify_nondeterministic_result(data, ARRAY_LEN, expected,
172                                        "Large array test case for none ordering");
173     }
174 
175     MPI_Win_free(&win);
176 
177     /* 3. Mix MAX_LOC/MIN_LOC and MPI_REPLACE */
178     if (me == 0) {
179         /* reset data on rank 0. */
180         memset((void *) data, 0, ARRAY_LEN * sizeof(twoint_t));
181     }
182 
183     MPI_Win_create(data, sizeof(twoint_t) * ARRAY_LEN, 1, MPI_INFO_NULL, MPI_COMM_WORLD, &win);
184 
185     MPI_Win_fence(0, win);
186 
187     /* Rank np-1 performs 2 WRITE to rank 0. */
188     /* Test MAXLOC */
189     /* 3.a. Single data test */
190     if (me == nproc - 1) {
191         MPI_Accumulate(mine_plus, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_MAXLOC, win);
192         MPI_Accumulate(mine, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_REPLACE, win);
193     }
194 
195     MPI_Win_fence(0, win);
196     if (me == 0) {
197         expected[0].loc = nproc - 1;
198         expected[0].val = nproc;
199         verify_result(data, 1, expected[0], "Single data test case for MAXLOC and REPLACE");
200     }
201 
202     if (me == 0) {
203         data[0].loc = 0;
204         data[0].val = 0;
205     }
206     MPI_Win_fence(0, win);
207     /* 3.b. Large array test */
208     if (me == nproc - 1) {
209         MPI_Accumulate(mine_plus, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_MAXLOC, win);
210         MPI_Accumulate(mine, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_REPLACE, win);
211     }
212 
213     MPI_Win_fence(0, win);
214     if (me == 0) {
215         verify_result(data, ARRAY_LEN, expected[0], "Large array test case for MAXLOC and REPLACE");
216     }
217 
218     /* Test MINLOC */
219     if (me == 0) {
220         for (i = 0; i < ARRAY_LEN; i++) {
221             data[i].loc = INT_MAX;
222             data[i].val = INT_MAX;
223         }
224     }
225     MPI_Win_fence(0, win);
226     /* Rank np-1 performs 2 WRITE to rank 0. */
227     /* 3.c. Single data test */
228     if (me == nproc - 1) {
229         MPI_Accumulate(mine_plus, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_REPLACE, win);
230         MPI_Accumulate(mine, 1, MPI_2INT, 0, 0, 1, MPI_2INT, MPI_MINLOC, win);
231     }
232 
233     MPI_Win_fence(0, win);
234     if (me == 0) {
235         expected[0].loc = nproc - 1;
236         expected[0].val = nproc;
237         verify_result(data, 1, expected[0], "Single data test case for REPLACE and MINLOC");
238     }
239 
240     if (me == 0) {
241         data[0].loc = INT_MAX;
242         data[0].val = INT_MAX;
243     }
244     MPI_Win_fence(0, win);
245     /* 3.d. Large array test */
246     if (me == nproc - 1) {
247         MPI_Accumulate(mine_plus, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_REPLACE, win);
248         MPI_Accumulate(mine, ARRAY_LEN, MPI_2INT, 0, 0, ARRAY_LEN, MPI_2INT, MPI_MINLOC, win);
249     }
250 
251     MPI_Win_fence(0, win);
252     if (me == 0) {
253         verify_result(data, ARRAY_LEN, expected[0], "Single data test case for REPLACE and MINLOC");
254     }
255 
256     MPI_Win_free(&win);
257     if (me == nproc - 1) {
258         free(mine);
259         free(mine_plus);
260     }
261     if (me == 0)
262         free(expected);
263 
264     MTest_Finalize(errs);
265     free(data);
266 
267     return MTestReturnValue(errs);
268 }
269