Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Include directory is in source_dir, not in binary_dir.
[simgrid.git] / teshsuite / smpi / mpich3-test / datatype / unusual-noncontigs.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *  (C) 2001 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6 #include <math.h>
7 #include <assert.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "mpi.h"
12
13 /* 
14    The default behavior of the test routines should be to briefly indicate
15    the cause of any errors - in this test, that means that verbose needs
16    to be set. Verbose should turn on output that is independent of error
17    levels.
18 */
19 static int verbose = 1;
20
21 int main(int argc, char *argv[]);
22 int parse_args(int argc, char **argv);
23 int struct_negdisp_test(void);
24 int vector_negstride_test(void);
25 int indexed_negdisp_test(void);
26 int struct_struct_test(void);
27 int flatten_test(void);
28
29 int build_array_section_type(MPI_Aint aext, MPI_Aint astart, MPI_Aint aend, MPI_Datatype *datatype);
30
31 int main(int argc, char *argv[])
32 {
33     int err, errs = 0;
34
35     /* Initialize MPI */
36     MPI_Init(&argc, &argv);
37     parse_args(argc, argv);
38
39     /* To improve reporting of problems about operations, we
40        change the error handler to errors return */
41     MPI_Comm_set_errhandler( MPI_COMM_WORLD, MPI_ERRORS_RETURN );
42
43     err = struct_negdisp_test();
44     if (verbose && err) fprintf(stderr, "error in struct_negdisp_test\n");
45     errs += err;
46
47     err = vector_negstride_test();
48     if (verbose && err) fprintf(stderr, "error in vector_negstride_test\n");
49     errs += err;
50
51     err = indexed_negdisp_test();
52     if (verbose && err) fprintf(stderr, "error in indexed_negdisp_test\n");
53     errs += err;
54
55     err = struct_struct_test();
56     if (verbose && err) fprintf(stderr, "error in struct_struct_test\n");
57     errs += err;
58
59     err = flatten_test();
60     if (verbose && err) fprintf(stderr, "error in flatten_test\n");
61     errs += err;
62
63     /* print message and exit */
64     if (errs) {
65         fprintf(stderr, "Found %d errors\n", errs);
66     }
67     else {
68         printf(" No Errors\n");
69     }
70     MPI_Finalize();
71     return 0;
72 }
73
74 /* test uses a struct type that describes data that is contiguous,
75  * but processed in a noncontiguous way.
76  */
77 int struct_negdisp_test(void)
78 {
79     int err, errs = 0;
80     int sendbuf[6] = { 1, 2, 3, 4, 5, 6 };
81     int recvbuf[6] = { -1, -2, -3, -4, -5, -6 };
82     MPI_Datatype mystruct;
83     MPI_Request request;
84     MPI_Status status;
85
86     MPI_Aint disps[2]     = { 0,       -1*((int) sizeof(int)) };
87     int blks[2]           = { 1,       1, };
88     MPI_Datatype types[2] = { MPI_INT, MPI_INT };
89
90     err = MPI_Type_struct(2, blks, disps, types, &mystruct);
91     if (err != MPI_SUCCESS) {
92         errs++;
93         if (verbose) {
94             fprintf(stderr, "MPI_Type_struct returned error\n");
95         }
96     }
97
98     MPI_Type_commit(&mystruct);
99
100     err = MPI_Irecv(recvbuf+1, 4, MPI_INT, 0, 0, MPI_COMM_SELF, &request);
101     if (err != MPI_SUCCESS) {
102         errs++;
103         if (verbose) {
104             fprintf(stderr, "MPI_Irecv returned error\n");
105         }
106     }
107
108     err = MPI_Send(sendbuf+2, 2, mystruct, 0, 0, MPI_COMM_SELF);
109     if (err != MPI_SUCCESS) {
110         errs++;
111         if (verbose) {
112             fprintf(stderr, "MPI_Send returned error\n");
113         }
114     }
115
116     err = MPI_Wait(&request, &status);
117     if (err != MPI_SUCCESS) {
118         errs++;
119         if (verbose) {
120             fprintf(stderr, "MPI_Wait returned error\n");
121         }
122     }
123
124     /* verify data */
125     if (recvbuf[0] != -1) {
126         errs++;
127         if (verbose) {
128             fprintf(stderr, "recvbuf[0] = %d; should be %d\n", recvbuf[0], -1);
129         }
130     }
131     if (recvbuf[1] != 3) {
132         errs++;
133         if (verbose) {
134             fprintf(stderr, "recvbuf[1] = %d; should be %d\n", recvbuf[1], 3);
135         }
136     }
137     if (recvbuf[2] != 2) {
138         errs++;
139         if (verbose) {
140             fprintf(stderr, "recvbuf[2] = %d; should be %d\n", recvbuf[2], 2);
141         }
142     }
143     if (recvbuf[3] != 5) {
144         errs++;
145         if (verbose) {
146             fprintf(stderr, "recvbuf[3] = %d; should be %d\n", recvbuf[3], 5);
147         }
148     }
149     if (recvbuf[4] != 4) {
150         errs++;
151         if (verbose) {
152             fprintf(stderr, "recvbuf[4] = %d; should be %d\n", recvbuf[4], 4);
153         }
154     }
155     if (recvbuf[5] != -6) {
156         errs++;
157         if (verbose) {
158             fprintf(stderr, "recvbuf[5] = %d; should be %d\n", recvbuf[5], -6);
159         }
160     }
161
162     MPI_Type_free(&mystruct);
163
164     return errs;
165 }
166
167 /* test uses a vector type that describes data that is contiguous,
168  * but processed in a noncontiguous way.  this is effectively the
169  * same type as in the struct_negdisp_test above.
170  */
171 int vector_negstride_test(void)
172 {
173     int err, errs = 0;
174     int sendbuf[6] = { 1, 2, 3, 4, 5, 6 };
175     int recvbuf[6] = { -1, -2, -3, -4, -5, -6 };
176     MPI_Datatype myvector;
177     MPI_Request request;
178     MPI_Status status;
179
180     err = MPI_Type_vector(2, 1, -1, MPI_INT, &myvector);
181     if (err != MPI_SUCCESS) {
182         errs++;
183         if (verbose) {
184             fprintf(stderr, "MPI_Type_vector returned error\n");
185         }
186     }
187
188     MPI_Type_commit(&myvector);
189
190     err = MPI_Irecv(recvbuf+1, 4, MPI_INT, 0, 0, MPI_COMM_SELF, &request);
191     if (err != MPI_SUCCESS) {
192         errs++;
193         if (verbose) {
194             fprintf(stderr, "MPI_Irecv returned error\n");
195         }
196     }
197
198     err = MPI_Send(sendbuf+2, 2, myvector, 0, 0, MPI_COMM_SELF);
199     if (err != MPI_SUCCESS) {
200         errs++;
201         if (verbose) {
202             fprintf(stderr, "MPI_Send returned error\n");
203         }
204     }
205
206     err = MPI_Wait(&request, &status);
207     if (err != MPI_SUCCESS) {
208         errs++;
209         if (verbose) {
210             fprintf(stderr, "MPI_Wait returned error\n");
211         }
212     }
213
214     /* verify data */
215     if (recvbuf[0] != -1) {
216         errs++;
217         if (verbose) {
218             fprintf(stderr, "recvbuf[0] = %d; should be %d\n", recvbuf[0], -1);
219         }
220     }
221     if (recvbuf[1] != 3) {
222         errs++;
223         if (verbose) {
224             fprintf(stderr, "recvbuf[1] = %d; should be %d\n", recvbuf[1], 3);
225         }
226     }
227     if (recvbuf[2] != 2) {
228         errs++;
229         if (verbose) {
230             fprintf(stderr, "recvbuf[2] = %d; should be %d\n", recvbuf[2], 2);
231         }
232     }
233     if (recvbuf[3] != 5) {
234         errs++;
235         if (verbose) {
236             fprintf(stderr, "recvbuf[3] = %d; should be %d\n", recvbuf[3], 5);
237         }
238     }
239     if (recvbuf[4] != 4) {
240         errs++;
241         if (verbose) {
242             fprintf(stderr, "recvbuf[4] = %d; should be %d\n", recvbuf[4], 4);
243         }
244     }
245     if (recvbuf[5] != -6) {
246         errs++;
247         if (verbose) {
248             fprintf(stderr, "recvbuf[5] = %d; should be %d\n", recvbuf[5], -6);
249         }
250     }
251
252     MPI_Type_free(&myvector);
253
254     return errs;
255 }
256
257 /* test uses a indexed type that describes data that is contiguous,
258  * but processed in a noncontiguous way.  this is effectively the same
259  * type as in the two tests above.
260  */
261 int indexed_negdisp_test(void)
262 {
263     int err, errs = 0;
264     int sendbuf[6] = { 1, 2, 3, 4, 5, 6 };
265     int recvbuf[6] = { -1, -2, -3, -4, -5, -6 };
266     MPI_Datatype myindexed;
267     MPI_Request request;
268     MPI_Status status;
269
270     int disps[2]     = { 0, -1 };
271     int blks[2]           = { 1, 1 };
272
273     err = MPI_Type_indexed(2, blks, disps, MPI_INT, &myindexed);
274     if (err != MPI_SUCCESS) {
275         errs++;
276         if (verbose) {
277             fprintf(stderr, "MPI_Type_indexed returned error\n");
278         }
279     }
280
281     MPI_Type_commit(&myindexed);
282
283     err = MPI_Irecv(recvbuf+1, 4, MPI_INT, 0, 0, MPI_COMM_SELF, &request);
284     if (err != MPI_SUCCESS) {
285         errs++;
286         if (verbose) {
287             fprintf(stderr, "MPI_Irecv returned error\n");
288         }
289     }
290
291     err = MPI_Send(sendbuf+2, 2, myindexed, 0, 0, MPI_COMM_SELF);
292     if (err != MPI_SUCCESS) {
293         errs++;
294         if (verbose) {
295             fprintf(stderr, "MPI_Send returned error\n");
296         }
297     }
298
299     err = MPI_Wait(&request, &status);
300     if (err != MPI_SUCCESS) {
301         errs++;
302         if (verbose) {
303             fprintf(stderr, "MPI_Wait returned error\n");
304         }
305     }
306
307     /* verify data */
308     if (recvbuf[0] != -1) {
309         errs++;
310         if (verbose) {
311             fprintf(stderr, "recvbuf[0] = %d; should be %d\n", recvbuf[0], -1);
312         }
313     }
314     if (recvbuf[1] != 3) {
315         errs++;
316         if (verbose) {
317             fprintf(stderr, "recvbuf[1] = %d; should be %d\n", recvbuf[1], 3);
318         }
319     }
320     if (recvbuf[2] != 2) {
321         errs++;
322         if (verbose) {
323             fprintf(stderr, "recvbuf[2] = %d; should be %d\n", recvbuf[2], 2);
324         }
325     }
326     if (recvbuf[3] != 5) {
327         errs++;
328         if (verbose) {
329             fprintf(stderr, "recvbuf[3] = %d; should be %d\n", recvbuf[3], 5);
330         }
331     }
332     if (recvbuf[4] != 4) {
333         errs++;
334         if (verbose) {
335             fprintf(stderr, "recvbuf[4] = %d; should be %d\n", recvbuf[4], 4);
336         }
337     }
338     if (recvbuf[5] != -6) {
339         errs++;
340         if (verbose) {
341             fprintf(stderr, "recvbuf[5] = %d; should be %d\n", recvbuf[5], -6);
342         }
343     }
344
345     MPI_Type_free(&myindexed);
346
347     return errs;
348 }
349
350 #define check_err(fn_name_)                                                   \
351     do {                                                                      \
352         if (err != MPI_SUCCESS) {                                             \
353             errs++;                                                           \
354             if (verbose) {                                                    \
355                 int len_;                                                     \
356                 char err_str_[MPI_MAX_ERROR_STRING];                          \
357                 MPI_Error_string(err, err_str_, &len_);                       \
358                 fprintf(stderr, #fn_name_ " failed at line %d, err=%d: %s\n", \
359                         __LINE__, err, err_str_);                             \
360             }                                                                 \
361         }                                                                     \
362     } while (0)
363 /* test case from tt#1030 ported to C
364  *
365  * Thanks to Matthias Lieber for reporting the bug and providing a good test
366  * program. */
367 int struct_struct_test(void)
368 {
369     int err, errs = 0;
370     int i, j, dt_size = 0;
371     MPI_Request req[2];
372
373
374 #define COUNT (2)
375     MPI_Aint displ[COUNT];
376     int blens[COUNT];
377     MPI_Datatype types[COUNT];
378     MPI_Datatype datatype;
379
380     /* A slight difference from the F90 test: F90 arrays are column-major, C
381      * arrays are row-major.  So we invert the order of dimensions. */
382 #define N (2)
383 #define M (4)
384     int array[N][M] =    { {-1, -1, -1, -1}, {-1, -1, -1, -1} };
385     int expected[N][M] = { {-1,  1,  2,  5}, {-1,  3,  4,  6} };
386     int seq_array[N*M];
387     MPI_Aint astart, aend;
388     MPI_Aint size_exp = 0;
389
390     /* 1st section selects elements 1 and 2 out of 2nd dimension, complete 1st dim.
391      * should receive the values 1, 2, 3, 4 */
392     astart = 1;
393     aend   = 2;
394     err = build_array_section_type(M, astart, aend, &types[0]);
395     if (err) {
396         errs++;
397         if (verbose) fprintf(stderr, "build_array_section_type failed\n");
398         return errs;
399     }
400     blens[0] = N;
401     displ[0] = 0;
402     size_exp = size_exp + N * (aend-astart+1) * sizeof(int);
403
404     /* 2nd section selects last element of 2nd dimension, complete 1st dim.
405      * should receive the values 5, 6 */
406     astart = 3;
407     aend   = 3;
408     err = build_array_section_type(M, astart, aend, &types[1]);
409     if (err) {
410         errs++;
411         if (verbose) fprintf(stderr, "build_array_section_type failed\n");
412         return errs;
413     }
414     blens[1] = N;
415     displ[1] = 0;
416     size_exp = size_exp + N * (aend-astart+1) * sizeof(int);
417
418     /* create type */
419     err = MPI_Type_create_struct(COUNT, blens, displ, types, &datatype);
420     check_err(MPI_Type_create_struct);
421     err = MPI_Type_commit(&datatype);
422     check_err(MPI_Type_commit);
423
424     err = MPI_Type_size(datatype, &dt_size);
425     check_err(MPI_Type_size);
426     if (dt_size != size_exp) {
427         errs++;
428         if (verbose) fprintf(stderr, "unexpected type size\n");
429     }
430
431
432     /* send the type to ourselves to make sure that the type describes data correctly */
433     for (i = 0; i < (N*M) ; ++i)
434         seq_array[i] = i + 1; /* source values 1..(N*M) */
435     err = MPI_Isend(&seq_array[0], dt_size/sizeof(int), MPI_INT, 0, 42, MPI_COMM_SELF, &req[0]);
436     check_err(MPI_Isend);
437     err = MPI_Irecv(&array[0][0], 1, datatype, 0, 42, MPI_COMM_SELF, &req[1]);
438     check_err(MPI_Irecv);
439     err = MPI_Waitall(2, req, MPI_STATUSES_IGNORE);
440     check_err(MPI_Waitall);
441
442     /* check against expected */
443     for (i = 0; i < N; ++i) {
444         for (j = 0; j < M; ++j) {
445             if (array[i][j] != expected[i][j]) {
446                 errs++;
447                 if (verbose)
448                     fprintf(stderr, "array[%d][%d]=%d, should be %d\n", i, j, array[i][j], expected[i][j]);
449             }
450         }
451     }
452
453     err = MPI_Type_free(&datatype);
454     check_err(MPI_Type_free);
455     err = MPI_Type_free(&types[0]);
456     check_err(MPI_Type_free);
457     err = MPI_Type_free(&types[1]);
458     check_err(MPI_Type_free);
459
460     return errs;
461 #undef M
462 #undef N
463 #undef COUNT
464 }
465
466 /*   create a datatype for a 1D int array subsection
467
468      - a subsection of the first dimension is defined via astart, aend
469      - indexes are assumed to start with 0, that means:
470        - 0 <= astart <= aend < aext
471      - astart and aend are inclusive
472
473      example:
474
475      aext = 8, astart=2, aend=4 would produce:
476
477      index     | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
478      1D array   ###############################
479      datatype   LB      ###########             UB
480  */
481 int build_array_section_type(MPI_Aint aext, MPI_Aint astart, MPI_Aint aend, MPI_Datatype *datatype)
482 {
483 #define COUNT (3)
484     int err, errs = 0;
485     MPI_Aint displ[COUNT];
486     int blens[COUNT];
487     MPI_Datatype types[COUNT];
488
489     *datatype = MPI_DATATYPE_NULL;
490
491     /* lower bound marker */
492     types[0] = MPI_LB;
493     displ[0] = 0;
494     blens[0] = 1;
495
496     /* subsection starting at astart */
497     displ[1] = astart * sizeof(int);
498     types[1] = MPI_INT;
499     blens[1] = aend - astart + 1;
500
501     /* upper bound marker */
502     types[2] = MPI_UB;
503     displ[2] = aext * sizeof(int);
504     blens[2] = 1;
505
506     err = MPI_Type_create_struct(COUNT, blens, displ, types, datatype);
507     if (err != MPI_SUCCESS) {
508         errs++;
509         if (verbose) {
510             fprintf(stderr, "MPI_Type_create_struct failed, err=%d\n", err);
511         }
512     }
513
514     return errs;
515 #undef COUNT
516 }
517
518 /* start_idx is the "zero" point for the unpack */
519 static int pack_and_check_expected(MPI_Datatype type, const char *name,
520                                    int start_idx, int size,
521                                    int *array, int *expected)
522 {
523     int i;
524     int err, errs = 0;
525     int pack_size = -1;
526     int *pack_buf = NULL;
527     int pos;
528     int type_size = -1;
529     int sendbuf[8] = {0,1,2,3,4,5,6,7};
530
531     err = MPI_Type_size(type, &type_size);
532     check_err(MPI_Type_size);
533     assert(sizeof(sendbuf) >= type_size);
534
535     err = MPI_Pack_size(type_size/sizeof(int), MPI_INT, MPI_COMM_SELF, &pack_size);
536     check_err(MPI_Pack_size);
537     pack_buf = malloc(pack_size);
538     assert(pack_buf);
539
540     pos = 0;
541     err = MPI_Pack(&sendbuf[0], type_size/sizeof(int), MPI_INT, pack_buf, pack_size, &pos, MPI_COMM_SELF);
542     check_err(MPI_Pack);
543     pos = 0;
544     err = MPI_Unpack(pack_buf, pack_size, &pos, &array[start_idx], 1, type, MPI_COMM_SELF);
545     check_err(MPI_Unpack);
546     free(pack_buf);
547
548     /* check against expected */
549     for (i = 0; i < size; ++i) {
550         if (array[i] != expected[i]) {
551             errs++;
552             if (verbose)
553                 fprintf(stderr, "%s: array[%d]=%d, should be %d\n", name, i, array[i], expected[i]);
554         }
555     }
556
557     return errs;
558 }
559
560 /* regression for tt#1030, checks for bad offset math in the
561  * blockindexed and indexed dataloop flattening code */
562 int flatten_test(void)
563 {
564     int err, errs = 0;
565 #define ARR_SIZE (9)
566     /* real indices              0  1  2  3  4  5  6  7  8
567      * indices w/ &array[3]     -3 -2 -1  0  1  2  3  4  5 */
568     int array[ARR_SIZE]      = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
569     int expected[ARR_SIZE]   = {-1, 0, 1,-1, 2,-1, 3,-1, 4};
570     MPI_Datatype idx_type = MPI_DATATYPE_NULL;
571     MPI_Datatype blkidx_type = MPI_DATATYPE_NULL;
572     MPI_Datatype combo = MPI_DATATYPE_NULL;
573 #define COUNT (2)
574     int displ[COUNT];
575     MPI_Aint adispl[COUNT];
576     int blens[COUNT];
577     MPI_Datatype types[COUNT];
578
579     /* indexed type layout:
580      * XX_X
581      * 2101  <-- pos (left of 0 is neg)
582      *
583      * different blens to prevent optimization into a blockindexed
584      */
585     blens[0] = 2;
586     displ[0] = -2; /* elements, puts byte after block end at 0 */
587     blens[1] = 1;
588     displ[1] = 1; /*elements*/
589
590     err = MPI_Type_indexed(COUNT, blens, displ, MPI_INT, &idx_type);
591     check_err(MPI_Type_indexed);
592     err = MPI_Type_commit(&idx_type);
593     check_err(MPI_Type_commit);
594
595     /* indexed type layout:
596      * _X_X
597      * 2101  <-- pos (left of 0 is neg)
598      */
599     displ[0] = -1;
600     displ[1] = 1;
601     err = MPI_Type_create_indexed_block(COUNT, 1, displ, MPI_INT, &blkidx_type);
602     check_err(MPI_Type_indexed_block);
603     err = MPI_Type_commit(&blkidx_type);
604     check_err(MPI_Type_commit);
605
606     /* struct type layout:
607      * II_I_B_B  (I=idx_type, B=blkidx_type)
608      * 21012345  <-- pos (left of 0 is neg)
609      */
610     blens[0]  = 1;
611     adispl[0] = 0; /*bytes*/
612     types[0]  = idx_type;
613
614     blens[1]  = 1;
615     adispl[1] = 4 * sizeof(int); /* bytes */
616     types[1]  = blkidx_type;
617
618     /* must be a struct in order to trigger flattening code */
619     err = MPI_Type_create_struct(COUNT, blens, adispl, types, &combo);
620     check_err(MPI_Type_indexed);
621     err = MPI_Type_commit(&combo);
622     check_err(MPI_Type_commit);
623
624     /* pack/unpack with &array[3] */
625     errs += pack_and_check_expected(combo, "combo", 3, ARR_SIZE, array, expected);
626
627     MPI_Type_free(&combo);
628     MPI_Type_free(&idx_type);
629     MPI_Type_free(&blkidx_type);
630
631     return errs;
632 #undef COUNT
633 }
634 #undef check_err
635
636 int parse_args(int argc, char **argv)
637 {
638     /*
639     int ret;
640
641     while ((ret = getopt(argc, argv, "v")) >= 0)
642     {
643         switch (ret) {
644             case 'v':
645                 verbose = 1;
646                 break;
647         }
648     }
649     */
650     if (argc > 1 && strcmp(argv[1], "-v") == 0)
651         verbose = 1;
652     return 0;
653 }