tests/vg_regtest: Always evaluate prerequisite expressions with sh
[valgrind.git] / mpi / mpiwrap_type_test.c
blobbac0be4af58dd1ee0dbc79816d720da3c3721b07
2 /* A test program to check whether the type-traversal functions in
3 mpiwrap.c (walk_type, walk_type_array) are correct. It does this
4 by sending a message to itself, thereby discovering what areas of
5 memory the MPI implementation itself believe constitute the type.
6 It then gets walk_type to enumerate the type, and compares the
7 results. */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <assert.h>
13 #include "mpi.h"
14 #include "../memcheck/memcheck.h"
16 typedef MPI_Datatype Ty;
18 typedef unsigned char Bool;
19 #define False ((Bool)0)
20 #define True ((Bool)1)
22 void* walk_type_fn = NULL;
24 static Ty tycon_Contiguous ( int count, Ty t )
26 Ty t2;
27 int r = MPI_Type_contiguous( count, t, &t2 );
28 assert(r == MPI_SUCCESS);
29 return t2;
32 static Ty tycon_Struct2 ( int d1, int copies1, Ty t1,
33 int d2, int copies2, Ty t2 )
35 int blocklens[2];
36 MPI_Aint disps[2];
37 Ty tys[2];
38 Ty tres;
39 int r;
40 blocklens[0] = copies1;
41 blocklens[1] = copies2;
42 disps[0] = d1;
43 disps[1] = d2;
44 tys[0] = t1;
45 tys[1] = t2;
46 r = MPI_Type_struct( 2, blocklens, disps, tys, &tres );
47 assert(r == MPI_SUCCESS);
48 return tres;
51 static Ty tycon_Vector ( int count, int blocklen, int stride, Ty t )
53 Ty tres;
54 int r;
55 r = MPI_Type_vector( count, blocklen, stride, t, &tres );
56 assert(r == MPI_SUCCESS);
57 return tres;
60 static Ty tycon_HVector ( int count, int blocklen, MPI_Aint stride, Ty t )
62 Ty tres;
63 int r;
64 r = MPI_Type_hvector( count, blocklen, stride, t, &tres );
65 assert(r == MPI_SUCCESS);
66 return tres;
69 static Ty tycon_Indexed2 ( int d1, int copies1,
70 int d2, int copies2, Ty t )
72 int blocklens[2];
73 int disps[2];
74 Ty tres;
75 int r;
76 blocklens[0] = copies1;
77 blocklens[1] = copies2;
78 disps[0] = d1;
79 disps[1] = d2;
80 r = MPI_Type_indexed( 2, blocklens, disps, t, &tres );
81 assert(r == MPI_SUCCESS);
82 return tres;
85 static Ty tycon_HIndexed2 ( MPI_Aint d1, int copies1,
86 MPI_Aint d2, int copies2, Ty t )
88 int blocklens[2];
89 MPI_Aint disps[2];
90 Ty tres;
91 int r;
92 blocklens[0] = copies1;
93 blocklens[1] = copies2;
94 disps[0] = d1;
95 disps[1] = d2;
96 r = MPI_Type_hindexed( 2, blocklens, disps, t, &tres );
97 assert(r == MPI_SUCCESS);
98 return tres;
101 /* ------------------------------ */
103 char characterise ( unsigned char b )
105 if (b == 0x00) return 'D';
106 if (b == 0xFF) return '.';
107 return '?';
110 void sendToMyself_callback( void* v, long n )
112 long i;
113 unsigned char* p = (unsigned char*)v;
114 if (0) printf("callback: %p %ld\n", v, n);
115 for (i = 0; i < n; i++)
116 p[i] = 0x00;
119 void sendToMyself ( Bool commit_free, Ty* tyP, char* name )
121 int i;
122 MPI_Aint lb, ub, ex;
123 MPI_Request req;
124 MPI_Status status;
125 char* sbuf;
126 char* rbuf;
127 char* rbuf_walk;
128 int r;
130 /* C: what a fabulous functional programming language :-) */
131 void(*dl_walk_type)(void(*)(void*,long),char*,MPI_Datatype)
132 = (void(*)(void(*)(void*,long),char*,MPI_Datatype))
133 walk_type_fn;
135 if (!dl_walk_type) {
136 printf("sendToMyself: can't establish type walker fn\n");
137 return;
140 printf("\nsendToMyself: trying %s\n", name);
142 if (commit_free) {
143 r = MPI_Type_commit( tyP );
144 assert(r == MPI_SUCCESS);
147 r = MPI_Type_lb( *tyP, &lb );
148 assert(r == MPI_SUCCESS);
149 r = MPI_Type_ub( *tyP, &ub );
150 assert(r == MPI_SUCCESS);
151 r = MPI_Type_extent( *tyP, &ex );
152 assert(r == MPI_SUCCESS);
153 printf("sendToMyself: ex=%d (%d,%d)\n", (int)ex, (int)lb, (int)ub);
154 assert(lb >= 0);
156 /* Fill send buffer with zeroes */
157 sbuf = malloc(ub);
158 assert(sbuf);
159 for (i = 0; i < ub; i++)
160 sbuf[i] = 0;
162 r = MPI_Isend( sbuf,1,*tyP, 0,99,MPI_COMM_WORLD, &req);
163 assert(r == MPI_SUCCESS);
165 /* Fill recv buffer with 0xFFs */
166 rbuf = malloc(ub);
167 assert(rbuf);
168 for (i = 0; i < ub; i++)
169 rbuf[i] = 0xFF;
171 r = MPI_Recv( rbuf,1,*tyP, 0,99,MPI_COMM_WORLD, &status);
172 assert(r == MPI_SUCCESS);
174 /* Now: rbuf should contain 0x00s where data was transferred and
175 undefined 0xFFs where data was not transferred. Get
176 libmpiwrap.so to walk the transferred type, using the callback
177 to set to 0x00 all parts of rbuf_walk it considers part of the
178 type. */
180 rbuf_walk = malloc(ub);
181 assert(rbuf_walk);
182 for (i = 0; i < ub; i++)
183 rbuf_walk[i] = 0xFF;
185 dl_walk_type( sendToMyself_callback, rbuf_walk, *tyP );
187 if (commit_free) {
188 r = MPI_Type_free( tyP );
189 assert(r == MPI_SUCCESS);
192 for (i = 0; i < ub; i++) {
193 if (rbuf_walk[i] == rbuf[i])
194 continue; /* ok */
195 else
196 break; /* discrepancy */
199 if (i == ub)
200 printf("SUCCESS\n");
201 else
202 printf("FAILED\n");
204 printf(" libmpiwrap=");
205 for (i = 0; i < ub; i++)
206 printf("%c", characterise(rbuf_walk[i]));
207 printf("\n");
209 printf("MPI library=");
210 for (i = 0; i < ub; i++)
211 printf("%c", characterise(rbuf[i]));
212 printf("\n");
214 free(sbuf);
215 free(rbuf);
216 free(rbuf_walk);
220 typedef char* Nm;
222 int main ( int argc, char** argv )
224 int rank, size;
225 char* opts;
227 if (!RUNNING_ON_VALGRIND) {
228 printf("error: this program must be run on valgrind\n");
229 return 1;
231 opts = getenv("MPIWRAP_DEBUG");
232 if ((!opts) || NULL==strstr(opts, "initkludge")) {
233 printf("error: program requires MPIWRAP_DEBUG=initkludge\n");
234 return 1;
237 /* Note: this trick doesn't work on 64-bit platforms,
238 since MPI_Init returns int. */
239 walk_type_fn = (void*)(long) MPI_Init( &argc, &argv );
240 printf("mpiwrap_type_test: walk_type_fn = %p\n", walk_type_fn);
241 assert(walk_type_fn);
243 MPI_Comm_size( MPI_COMM_WORLD, &size );
244 MPI_Comm_rank( MPI_COMM_WORLD, &rank );
246 if (rank == 0) {
248 #define TRY(_commit_free,_type,_name) \
249 do { Ty ty = (_type); \
250 Nm nm = (_name); \
251 sendToMyself((_commit_free), &ty, nm); \
252 } while (0)
254 TRY(True, tycon_Contiguous(3, MPI_INT),
255 "Contig{3xINT}");
257 TRY(True, tycon_Struct2(3,2,MPI_CHAR, 8,1,MPI_DOUBLE),
258 "Struct{h3:2xCHAR, h8:1xDOUBLE}");
260 TRY(True, tycon_Struct2(0,1,MPI_CHAR, 8,1,tycon_Contiguous(4, MPI_DOUBLE)),
261 "Struct{h0:1xCHAR, h8:1xContig{4xDOUBLE}}");
263 TRY(True, tycon_Contiguous(10, tycon_Struct2(1,1,MPI_CHAR, 4,1,MPI_FLOAT)),
264 "Contig{10xStruct{h1:1xCHAR, h4:1xFLOAT}}");
266 TRY(True, tycon_Vector(5, 2,3,MPI_DOUBLE),
267 "Vector{5x(2,3)xDOUBLE}");
269 TRY(True, tycon_Vector(3, 1,2,MPI_LONG_DOUBLE),
270 "Vector{3x(1,2)xLONG_DOUBLE}");
272 TRY(True, tycon_HVector(4, 1,3,MPI_SHORT),
273 "HVector{4x(1,h3)xSHORT}");
275 TRY(True, tycon_Indexed2(1,3, 5,2, MPI_UNSIGNED_CHAR),
276 "Indexed{1:3x,5:2x,UNSIGNED_CHAR}");
278 TRY(True, tycon_HIndexed2(1,2, 6,3, MPI_UNSIGNED_SHORT),
279 "HIndexed{h1:2x,h6:3x,UNSIGNED_SHORT}");
281 TRY(False, MPI_FLOAT_INT, "FLOAT_INT");
282 TRY(False, MPI_DOUBLE_INT, "DOUBLE_INT");
283 TRY(False, MPI_LONG_INT, "LONG_INT");
284 TRY(False, MPI_SHORT_INT, "SHORT_INT");
285 TRY(False, MPI_2INT, "2INT");
286 TRY(False, MPI_LONG_DOUBLE_INT, "LONG_DOUBLE_INT");
288 /* The next 4 don't seem to exist on openmpi-1.2.2. */
290 #if defined(MPI_REAL8)
291 TRY(False, MPI_REAL8, "REAL8");
292 #endif
293 #if defined(MPI_REAL4)
294 TRY(False, MPI_REAL4, "REAL4");
295 #endif
296 #if defined(MPI_INTEGER8)
297 TRY(False, MPI_INTEGER8, "INTEGER8");
298 #endif
299 #if defined(MPI_INTEGER4)
300 TRY(False, MPI_INTEGER4, "INTEGER4");
301 #endif
303 TRY(False, MPI_COMPLEX, "COMPLEX");
304 TRY(False, MPI_DOUBLE_COMPLEX, "DOUBLE_COMPLEX");
306 // On openmpi-1.2.2 on x86-linux, sendToMyself bombs openmpi,
307 // for some reason (openmpi thinks these all have zero size/extent
308 // and therefore can't be MPI_Send-ed, AIUI).
309 // TRY(False, MPI_LOGICAL, "LOGICAL");
310 // TRY(False, MPI_REAL, "REAL");
311 // TRY(False, MPI_DOUBLE_PRECISION, "DOUBLE_PRECISION");
312 // TRY(False, MPI_INTEGER, "INTEGER");
313 TRY(False, MPI_2INTEGER, "2INTEGER");
314 TRY(False, MPI_2COMPLEX, "2COMPLEX");
315 TRY(False, MPI_2DOUBLE_COMPLEX, "2DOUBLE_COMPLEX");
316 TRY(False, MPI_2REAL, "2REAL");
317 TRY(False, MPI_2DOUBLE_PRECISION, "2DOUBLE_PRECISION");
318 TRY(False, MPI_CHARACTER, "CHARACTER");
320 /* The following from a table in chapter 9 of the MPI2 spec
321 date Nov 15, 2003, page 247. */
322 TRY(False, MPI_PACKED, "PACKED");
323 TRY(False, MPI_BYTE, "BYTE");
324 TRY(False, MPI_CHAR, "CHAR");
325 TRY(False, MPI_UNSIGNED_CHAR, "UNSIGNED_CHAR");
326 TRY(False, MPI_SIGNED_CHAR, "SIGNED_CHAR");
327 TRY(False, MPI_WCHAR, "WCHAR");
328 TRY(False, MPI_SHORT, "SHORT");
329 TRY(False, MPI_UNSIGNED_SHORT, "UNSIGNED_SHORT");
330 TRY(False, MPI_INT, "INT");
331 TRY(False, MPI_UNSIGNED, "UNSIGNED");
332 TRY(False, MPI_LONG, "LONG");
333 TRY(False, MPI_UNSIGNED_LONG, "UNSIGNED_LONG");
334 TRY(False, MPI_FLOAT, "FLOAT");
335 TRY(False, MPI_DOUBLE, "DOUBLE");
336 TRY(False, MPI_LONG_DOUBLE, "LONG_DOUBLE");
337 TRY(False, MPI_CHARACTER, "CHARACTER");
339 // Same deal as above
340 // TRY(False, MPI_LOGICAL, "LOGICAL");
341 // TRY(False, MPI_INTEGER, "INTEGER");
342 // TRY(False, MPI_REAL, "REAL");
343 // TRY(False, MPI_DOUBLE_PRECISION, "DOUBLE_PRECISION");
345 TRY(False, MPI_COMPLEX, "COMPLEX");
346 TRY(False, MPI_DOUBLE_COMPLEX, "DOUBLE_COMPLEX");
347 #if defined(MPI_INTEGER1)
348 TRY(False, MPI_INTEGER1, "INTEGER1");
349 #endif
350 #if defined(MPI_INTEGER2)
351 TRY(False, MPI_INTEGER2, "INTEGER2");
352 #endif
353 #if defined(MPI_INTEGER4)
354 TRY(False, MPI_INTEGER4, "INTEGER4");
355 #endif
356 #if defined(MPI_INTEGER8)
357 TRY(False, MPI_INTEGER8, "INTEGER8");
358 #endif
359 TRY(False, MPI_LONG_LONG, "LONG_LONG");
360 TRY(False, MPI_UNSIGNED_LONG_LONG, "UNSIGNED_LONG_LONG");
361 #if defined(MPI_REAL4)
362 TRY(False, MPI_REAL4, "REAL4");
363 #endif
364 #if defined(MPI_REAL8)
365 TRY(False, MPI_REAL8, "REAL8");
366 #endif
367 #if defined(MPI_REAL16)
368 TRY(False, MPI_REAL16, "REAL16");
369 #endif
371 #undef TRY
375 MPI_Finalize();
376 return 0;