1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /*
15 * MPIO independent overlapping writes.
16 *
17 * First n-1 processes open 1 file.
18 * Each of the n-1 process writes chunks of data to the file in round-robin
19 * fashion, in a interleaved but not overlapped fashion. Using increasing
20 * chunk sizes for the benefits of testing different write sizes and also
21 * reducing the numbers of writes.
22 *
23 * Last process (n-1) just waits.
24 * First n-1 processes finish writing and cloose the file.
25 * Last process opens the same file and verifies the data.
26 */
27
28 #include "testpar.h"
29
30 /* FILENAME and filenames must have the same number of names */
31 const char *FILENAME[2]={
32 "MPItest",
33 NULL};
34 char filenames[2][200];
35 int nerrors = 0;
36 hid_t fapl; /* file access property list */
37
38 /* protocols */
39 static int errors_sum(int nerrs);
40
41 #define MPIO_TEST_WRITE_SIZE 1024*1024 /* 1 MB */
42
43 static int
test_mpio_overlap_writes(char * filename)44 test_mpio_overlap_writes(char *filename)
45 {
46 int mpi_size, mpi_rank;
47 MPI_Comm comm;
48 MPI_Info info = MPI_INFO_NULL;
49 int color, mrc;
50 MPI_File fh;
51 int i;
52 int vrfyerrs, nerrs;
53 unsigned char buf[4093]; /* use some prime number for size */
54 int bufsize = sizeof(buf);
55 MPI_Offset stride;
56 MPI_Offset mpi_off;
57 MPI_Status mpi_stat;
58
59
60 if (VERBOSE_MED)
61 printf("MPIO independent overlapping writes test on file %s\n",
62 filename);
63
64 nerrs = 0;
65 /* set up MPI parameters */
66 MPI_Comm_size(MPI_COMM_WORLD,&mpi_size);
67 MPI_Comm_rank(MPI_COMM_WORLD,&mpi_rank);
68
69 /* Need at least 2 processes */
70 if (mpi_size < 2) {
71 if (MAINPROCESS)
72 printf("Need at least 2 processes to run MPIO test.\n");
73 printf(" -SKIP- \n");
74 return 0;
75 }
76
77 /* splits processes 0 to n-2 into one comm. and the last one into another */
78 color = ((mpi_rank < (mpi_size - 1)) ? 0 : 1);
79 mrc = MPI_Comm_split (MPI_COMM_WORLD, color, mpi_rank, &comm);
80 VRFY((mrc==MPI_SUCCESS), "Comm_split succeeded");
81
82 if (color==0){
83 /* First n-1 processes (color==0) open a file and write it */
84 mrc = MPI_File_open(comm, filename, MPI_MODE_CREATE|MPI_MODE_RDWR,
85 info, &fh);
86 VRFY((mrc==MPI_SUCCESS), "");
87
88 stride = 1;
89 mpi_off = mpi_rank*stride;
90 while (mpi_off < MPIO_TEST_WRITE_SIZE){
91 /* make sure the write does not exceed the TEST_WRITE_SIZE */
92 if (mpi_off+stride > MPIO_TEST_WRITE_SIZE)
93 stride = MPIO_TEST_WRITE_SIZE - mpi_off;
94
95 /* set data to some trivial pattern for easy verification */
96 for (i=0; i<stride; i++)
97 buf[i] = (unsigned char)(mpi_off+i);
98 mrc = MPI_File_write_at(fh, mpi_off, buf, (int)stride, MPI_BYTE,
99 &mpi_stat);
100 VRFY((mrc==MPI_SUCCESS), "");
101
102 /* move the offset pointer to last byte written by all processes */
103 mpi_off += (mpi_size - 1 - mpi_rank) * stride;
104
105 /* Increase chunk size without exceeding buffer size. */
106 /* Then move the starting offset for next write. */
107 stride *= 2;
108 if (stride > bufsize)
109 stride = bufsize;
110 mpi_off += mpi_rank*stride;
111 }
112
113 /* close file and free the communicator */
114 mrc = MPI_File_close(&fh);
115 VRFY((mrc==MPI_SUCCESS), "MPI_FILE_CLOSE");
116 mrc = MPI_Comm_free(&comm);
117 VRFY((mrc==MPI_SUCCESS), "MPI_Comm_free");
118
119 /* sync with the other waiting processes */
120 mrc = MPI_Barrier(MPI_COMM_WORLD);
121 VRFY((mrc==MPI_SUCCESS), "Sync after writes");
122 }else{
123 /* last process waits till writes are done,
124 * then opens file to verify data.
125 */
126 mrc = MPI_Barrier(MPI_COMM_WORLD);
127 VRFY((mrc==MPI_SUCCESS), "Sync after writes");
128
129 mrc = MPI_File_open(comm, filename, MPI_MODE_RDONLY,
130 info, &fh);
131 VRFY((mrc==MPI_SUCCESS), "");
132
133 stride = bufsize;
134 for (mpi_off=0; mpi_off < MPIO_TEST_WRITE_SIZE; mpi_off += bufsize){
135 /* make sure it does not read beyond end of data */
136 if (mpi_off+stride > MPIO_TEST_WRITE_SIZE)
137 stride = MPIO_TEST_WRITE_SIZE - mpi_off;
138 mrc = MPI_File_read_at(fh, mpi_off, buf, (int)stride, MPI_BYTE,
139 &mpi_stat);
140 VRFY((mrc==MPI_SUCCESS), "");
141 vrfyerrs=0;
142 for (i=0; i<stride; i++){
143 unsigned char expected;
144 expected = (unsigned char)(mpi_off+i);
145 if ((expected != buf[i]) &&
146 (vrfyerrs++ < MAX_ERR_REPORT || VERBOSE_MED)) {
147 printf("proc %d: found data error at [%ld], expect %u, got %u\n",
148 mpi_rank, (long)(mpi_off+i), expected, buf[i]);
149 }
150 }
151 if (vrfyerrs > MAX_ERR_REPORT && !VERBOSE_MED)
152 printf("proc %d: [more errors ...]\n", mpi_rank);
153
154 nerrs += vrfyerrs;
155 }
156
157 /* close file and free the communicator */
158 mrc = MPI_File_close(&fh);
159 VRFY((mrc==MPI_SUCCESS), "MPI_FILE_CLOSE");
160 mrc = MPI_Comm_free(&comm);
161 VRFY((mrc==MPI_SUCCESS), "MPI_Comm_free");
162 }
163
164 /*
165 * one more sync to ensure all processes have done reading
166 * before ending this test.
167 */
168 mrc = MPI_Barrier(MPI_COMM_WORLD);
169 VRFY((mrc==MPI_SUCCESS), "Sync before leaving test");
170 return (nerrs);
171 }
172
173
174 #define MB 1048576 /* 1024*1024 == 2**20 */
175 #define GB 1073741824 /* 1024**3 == 2**30 */
176 #define TWO_GB_LESS1 2147483647 /* 2**31 - 1 */
177 #define FOUR_GB_LESS1 4294967295L /* 2**32 - 1 */
178 /*
179 * Verify that MPI_Offset exceeding 2**31 can be computed correctly.
180 * Print any failure as information only, not as an error so that this
181 * won't abort the remaining test or other separated tests.
182 *
183 * Test if MPIO can write file from under 2GB to over 2GB and then
184 * from under 4GB to over 4GB.
185 * Each process writes 1MB in round robin fashion.
186 * Then reads the file back in by reverse order, that is process 0
187 * reads the data of process n-1 and vice versa.
188 */
189 static int
test_mpio_gb_file(char * filename)190 test_mpio_gb_file(char *filename)
191 {
192 int mpi_size, mpi_rank;
193 MPI_Info info = MPI_INFO_NULL;
194 int mrc;
195 MPI_File fh;
196 int i, j, n;
197 int vrfyerrs;
198 int writerrs; /* write errors */
199 int nerrs;
200 int ntimes; /* how many times */
201 char *buf = NULL;
202 char expected;
203 MPI_Offset size;
204 MPI_Offset mpi_off;
205 MPI_Offset mpi_off_old;
206 MPI_Status mpi_stat;
207 int is_signed, sizeof_mpi_offset;
208
209 nerrs = 0;
210 /* set up MPI parameters */
211 MPI_Comm_size(MPI_COMM_WORLD,&mpi_size);
212 MPI_Comm_rank(MPI_COMM_WORLD,&mpi_rank);
213
214 if (VERBOSE_MED)
215 printf("MPI_Offset range test\n");
216
217 /* figure out the signness and sizeof MPI_Offset */
218 mpi_off = 0;
219 is_signed = ((MPI_Offset)(mpi_off - 1)) < 0;
220 sizeof_mpi_offset = (int)(sizeof(MPI_Offset));
221
222 /*
223 * Verify the sizeof MPI_Offset and correctness of handling multiple GB
224 * sizes.
225 */
226 if (MAINPROCESS){ /* only process 0 needs to check it*/
227 printf("MPI_Offset is %s %d bytes integeral type\n",
228 is_signed ? "signed" : "unsigned", (int)sizeof(MPI_Offset));
229 if (sizeof_mpi_offset <= 4 && is_signed){
230 printf("Skipped 2GB range test "
231 "because MPI_Offset cannot support it\n");
232 }else {
233 /* verify correctness of assigning 2GB sizes */
234 mpi_off = 2 * 1024 * (MPI_Offset)MB;
235 INFO((mpi_off>0), "2GB OFFSET assignment no overflow");
236 INFO((mpi_off-1)==TWO_GB_LESS1, "2GB OFFSET assignment succeed");
237
238 /* verify correctness of increasing from below 2 GB to above 2GB */
239 mpi_off = TWO_GB_LESS1;
240 for (i=0; i < 3; i++){
241 mpi_off_old = mpi_off;
242 mpi_off = mpi_off + 1;
243 /* no overflow */
244 INFO((mpi_off>0), "2GB OFFSET increment no overflow");
245 /* correct inc. */
246 INFO((mpi_off-1)==mpi_off_old, "2GB OFFSET increment succeed");
247 }
248 }
249
250 if (sizeof_mpi_offset <= 4){
251 printf("Skipped 4GB range test "
252 "because MPI_Offset cannot support it\n");
253 }else {
254 /* verify correctness of assigning 4GB sizes */
255 mpi_off = 4 * 1024 * (MPI_Offset)MB;
256 INFO((mpi_off>0), "4GB OFFSET assignment no overflow");
257 INFO((mpi_off-1)==FOUR_GB_LESS1, "4GB OFFSET assignment succeed");
258
259 /* verify correctness of increasing from below 4 GB to above 4 GB */
260 mpi_off = FOUR_GB_LESS1;
261 for (i=0; i < 3; i++){
262 mpi_off_old = mpi_off;
263 mpi_off = mpi_off + 1;
264 /* no overflow */
265 INFO((mpi_off>0), "4GB OFFSET increment no overflow");
266 /* correct inc. */
267 INFO((mpi_off-1)==mpi_off_old, "4GB OFFSET increment succeed");
268 }
269 }
270 }
271
272 /*
273 * Verify if we can write to a file of multiple GB sizes.
274 */
275 if (VERBOSE_MED)
276 printf("MPIO GB file test %s\n", filename);
277
278 if (sizeof_mpi_offset <= 4){
279 printf("Skipped GB file range test "
280 "because MPI_Offset cannot support it\n");
281 }else{
282 buf = HDmalloc(MB);
283 VRFY((buf!=NULL), "malloc succeed");
284
285 /* open a new file. Remove it first in case it exists. */
286 /* Must delete because MPI_File_open does not have a Truncate mode. */
287 /* Don't care if it has error. */
288 MPI_File_delete(filename, MPI_INFO_NULL);
289 MPI_Barrier(MPI_COMM_WORLD); /* prevent racing condition */
290
291 mrc = MPI_File_open(MPI_COMM_WORLD, filename, MPI_MODE_CREATE|MPI_MODE_RDWR,
292 info, &fh);
293 VRFY((mrc==MPI_SUCCESS), "MPI_FILE_OPEN");
294
295 printf("MPIO GB file write test %s\n", filename);
296
297 /* instead of writing every bytes of the file, we will just write
298 * some data around the 2 and 4 GB boundaries. That should cover
299 * potential integer overflow and filesystem size limits.
300 */
301 writerrs = 0;
302 for (n=2; n <= 4; n+=2){
303 ntimes = GB/MB*n/mpi_size + 1;
304 for (i=ntimes-2; i <= ntimes; i++){
305 mpi_off = (i*mpi_size + mpi_rank)*(MPI_Offset)MB;
306 if (VERBOSE_MED)
307 HDfprintf(stdout,"proc %d: write to mpi_off=%016llx, %lld\n",
308 mpi_rank, mpi_off, mpi_off);
309 /* set data to some trivial pattern for easy verification */
310 for (j=0; j<MB; j++)
311 *(buf+j) = i*mpi_size + mpi_rank;
312 if (VERBOSE_MED)
313 HDfprintf(stdout,"proc %d: writing %d bytes at offset %lld\n",
314 mpi_rank, MB, mpi_off);
315 mrc = MPI_File_write_at(fh, mpi_off, buf, MB, MPI_BYTE, &mpi_stat);
316 INFO((mrc==MPI_SUCCESS), "GB size file write");
317 if (mrc!=MPI_SUCCESS)
318 writerrs++;
319 }
320 }
321
322 /* close file and free the communicator */
323 mrc = MPI_File_close(&fh);
324 VRFY((mrc==MPI_SUCCESS), "MPI_FILE_CLOSE");
325
326 mrc = MPI_Barrier(MPI_COMM_WORLD);
327 VRFY((mrc==MPI_SUCCESS), "Sync after writes");
328
329 /*
330 * Verify if we can read the multiple GB file just created.
331 */
332 /* open it again to verify the data written */
333 /* but only if there was no write errors */
334 printf("MPIO GB file read test %s\n", filename);
335 if (errors_sum(writerrs)>0){
336 printf("proc %d: Skip read test due to previous write errors\n",
337 mpi_rank);
338 goto finish;
339 }
340 mrc = MPI_File_open(MPI_COMM_WORLD, filename, MPI_MODE_RDONLY, info, &fh);
341 VRFY((mrc==MPI_SUCCESS), "");
342
343 /* Only read back parts of the file that have been written. */
344 for (n=2; n <= 4; n+=2){
345 ntimes = GB/MB*n/mpi_size + 1;
346 for (i=ntimes-2; i <= ntimes; i++){
347 mpi_off = (i*mpi_size + (mpi_size - mpi_rank - 1))*(MPI_Offset)MB;
348 if (VERBOSE_MED)
349 HDfprintf(stdout,"proc %d: read from mpi_off=%016llx, %lld\n",
350 mpi_rank, mpi_off, mpi_off);
351 mrc = MPI_File_read_at(fh, mpi_off, buf, MB, MPI_BYTE, &mpi_stat);
352 INFO((mrc==MPI_SUCCESS), "GB size file read");
353 expected = i*mpi_size + (mpi_size - mpi_rank - 1);
354 vrfyerrs=0;
355 for (j=0; j<MB; j++){
356 if ((*(buf+j) != expected) &&
357 (vrfyerrs++ < MAX_ERR_REPORT || VERBOSE_MED)){
358 printf("proc %d: found data error at [%ld+%d], expect %d, got %d\n",
359 mpi_rank, (long)mpi_off, j, expected, *(buf+j));
360 }
361 }
362 if (vrfyerrs > MAX_ERR_REPORT && !VERBOSE_MED)
363 printf("proc %d: [more errors ...]\n", mpi_rank);
364
365 nerrs += vrfyerrs;
366 }
367 }
368
369 /* close file and free the communicator */
370 mrc = MPI_File_close(&fh);
371 VRFY((mrc==MPI_SUCCESS), "MPI_FILE_CLOSE");
372
373 /*
374 * one more sync to ensure all processes have done reading
375 * before ending this test.
376 */
377 mrc = MPI_Barrier(MPI_COMM_WORLD);
378 VRFY((mrc==MPI_SUCCESS), "Sync before leaving test");
379
380 printf("Test if MPI_File_get_size works correctly with %s\n", filename);
381
382 mrc = MPI_File_open(MPI_COMM_WORLD, filename, MPI_MODE_RDONLY, info, &fh);
383 VRFY((mrc==MPI_SUCCESS), "");
384
385 if (MAINPROCESS){ /* only process 0 needs to check it*/
386 mrc = MPI_File_get_size(fh, &size);
387 VRFY((mrc==MPI_SUCCESS), "");
388 VRFY((size == mpi_off+MB), "MPI_File_get_size doesn't return correct file size.");
389 }
390
391 /* close file and free the communicator */
392 mrc = MPI_File_close(&fh);
393 VRFY((mrc==MPI_SUCCESS), "MPI_FILE_CLOSE");
394
395 /*
396 * one more sync to ensure all processes have done reading
397 * before ending this test.
398 */
399 mrc = MPI_Barrier(MPI_COMM_WORLD);
400 VRFY((mrc==MPI_SUCCESS), "Sync before leaving test");
401 }
402
403 finish:
404 if (buf)
405 HDfree(buf);
406 return (nerrs);
407 }
408
409
410 /*
411 * MPI-IO Test: One writes, Many reads.
412 * Verify if only one process writes some data and then all other
413 * processes can read them back correctly. This tests if the
414 * underlaying parallel I/O and file system supports parallel I/O
415 * correctly.
416 *
417 * Algorithm: Only one process (e.g., process 0) writes some data.
418 * Then all processes, including the writing process, read the data
419 * back and verify them against the original values.
420 */
421
422 /*
423 * Default filename can be specified via first program argument.
424 * Each process writes something, then reads all data back.
425 */
426
427 #define DIMSIZE 32 /* Dimension size. */
428 #define PRINTID printf("Proc %d: ", mpi_rank)
429 #define USENONE 0
430 #define USEATOM 1 /* request atomic I/O */
431 #define USEFSYNC 2 /* request file_sync */
432
433
434 static int
test_mpio_1wMr(char * filename,int special_request)435 test_mpio_1wMr(char *filename, int special_request)
436 {
437 char hostname[128];
438 int mpi_size, mpi_rank;
439 MPI_File fh;
440 char mpi_err_str[MPI_MAX_ERROR_STRING];
441 int mpi_err_strlen;
442 int mpi_err;
443 unsigned char writedata[DIMSIZE], readdata[DIMSIZE];
444 unsigned char expect_val;
445 int i, irank;
446 int nerrs = 0; /* number of errors */
447 int atomicity;
448 MPI_Offset mpi_off;
449 MPI_Status mpi_stat;
450
451 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
452 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
453
454 if (MAINPROCESS && VERBOSE_MED){
455 printf("Testing one process writes, all processes read.\n");
456 printf("Using %d processes accessing file %s\n", mpi_size, filename);
457 printf(" (Filename can be specified via program argument)\n");
458 }
459
460 /* show the hostname so that we can tell where the processes are running */
461 if (VERBOSE_DEF){
462 if (gethostname(hostname, 128) < 0){
463 PRINTID;
464 printf("gethostname failed\n");
465 return 1;
466 }
467 PRINTID;
468 printf("hostname=%s\n", hostname);
469 }
470
471 /* Delete any old file in order to start anew. */
472 /* Must delete because MPI_File_open does not have a Truncate mode. */
473 /* Don't care if it has error. */
474 MPI_File_delete(filename, MPI_INFO_NULL);
475 MPI_Barrier(MPI_COMM_WORLD); /* prevent racing condition */
476
477 if ((mpi_err = MPI_File_open(MPI_COMM_WORLD, filename,
478 MPI_MODE_RDWR | MPI_MODE_CREATE ,
479 MPI_INFO_NULL, &fh))
480 != MPI_SUCCESS){
481 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
482 PRINTID;
483 printf("MPI_File_open failed (%s)\n", mpi_err_str);
484 return 1;
485 }
486
487 if (special_request & USEATOM){
488 /* ==================================================
489 * Set atomcity to true (1). A POSIX compliant filesystem
490 * should not need this.
491 * ==================================================*/
492 if ((mpi_err = MPI_File_get_atomicity(fh, &atomicity)) != MPI_SUCCESS){
493 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
494 PRINTID;
495 printf("MPI_File_get_atomicity failed (%s)\n", mpi_err_str);
496 }
497 if (VERBOSE_HI)
498 printf("Initial atomicity = %d\n", atomicity);
499 if ((mpi_err = MPI_File_set_atomicity(fh, 1)) != MPI_SUCCESS){
500 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
501 PRINTID;
502 printf("MPI_File_set_atomicity failed (%s)\n", mpi_err_str);
503 }
504 if ((mpi_err = MPI_File_get_atomicity(fh, &atomicity)) != MPI_SUCCESS){
505 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
506 PRINTID;
507 printf("MPI_File_get_atomicity failed (%s)\n", mpi_err_str);
508 }
509 if (VERBOSE_HI)
510 printf("After set_atomicity atomicity = %d\n", atomicity);
511 }
512
513 /* This barrier is not necessary but do it anyway. */
514 MPI_Barrier(MPI_COMM_WORLD);
515 if (VERBOSE_HI){
516 PRINTID;
517 printf("between MPI_Barrier and MPI_File_write_at\n");
518 }
519
520 /* ==================================================
521 * Each process calculates what to write but
522 * only process irank(0) writes.
523 * ==================================================*/
524 irank=0;
525 for (i=0; i < DIMSIZE; i++)
526 writedata[i] = irank*DIMSIZE + i;
527 mpi_off = irank*DIMSIZE;
528
529 /* Only one process writes */
530 if (mpi_rank==irank){
531 if (VERBOSE_HI){
532 PRINTID; printf("wrote %d bytes at %ld\n", DIMSIZE, (long)mpi_off);
533 }
534 if ((mpi_err = MPI_File_write_at(fh, mpi_off, writedata, DIMSIZE,
535 MPI_BYTE, &mpi_stat))
536 != MPI_SUCCESS){
537 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
538 PRINTID;
539 printf("MPI_File_write_at offset(%ld), bytes (%d), failed (%s)\n",
540 (long) mpi_off, DIMSIZE, mpi_err_str);
541 return 1;
542 };
543 };
544
545 /* Bcast the return code and */
546 /* make sure all writing are done before reading. */
547 MPI_Bcast(&mpi_err, 1, MPI_INT, irank, MPI_COMM_WORLD);
548 if (VERBOSE_HI){
549 PRINTID;
550 printf("MPI_Bcast: mpi_err = %d\n", mpi_err);
551 }
552
553 if (special_request & USEFSYNC){
554 /* ==================================================
555 * Do a file sync. A POSIX compliant filesystem
556 * should not need this.
557 * ==================================================*/
558 if (VERBOSE_HI)
559 printf("Apply MPI_File_sync\n");
560 /* call file_sync to force the write out */
561 if ((mpi_err = MPI_File_sync(fh)) != MPI_SUCCESS){
562 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
563 PRINTID;
564 printf("MPI_File_sync failed (%s)\n", mpi_err_str);
565 }
566 MPI_Barrier(MPI_COMM_WORLD);
567 /* call file_sync to force the write out */
568 if ((mpi_err = MPI_File_sync(fh)) != MPI_SUCCESS){
569 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
570 PRINTID;
571 printf("MPI_File_sync failed (%s)\n", mpi_err_str);
572 }
573 }
574
575 /* This barrier is not necessary because the Bcase or File_sync above */
576 /* should take care of it. Do it anyway. */
577 MPI_Barrier(MPI_COMM_WORLD);
578 if (VERBOSE_HI){
579 PRINTID;
580 printf("after MPI_Barrier\n");
581 }
582
583 /* ==================================================
584 * Each process reads what process 0 wrote and verify.
585 * ==================================================*/
586 irank=0;
587 mpi_off = irank*DIMSIZE;
588 if ((mpi_err = MPI_File_read_at(fh, mpi_off, readdata, DIMSIZE, MPI_BYTE,
589 &mpi_stat))
590 != MPI_SUCCESS){
591 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
592 PRINTID;
593 printf("MPI_File_read_at offset(%ld), bytes (%d), failed (%s)\n",
594 (long) mpi_off, DIMSIZE, mpi_err_str);
595 return 1;
596 };
597 for (i=0; i < DIMSIZE; i++){
598 expect_val = irank*DIMSIZE + i;
599 if (readdata[i] != expect_val){
600 PRINTID;
601 printf("read data[%d:%d] got %02x, expect %02x\n", irank, i,
602 readdata[i], expect_val);
603 nerrs++;
604 }
605 }
606
607 MPI_File_close(&fh);
608
609 if (VERBOSE_HI){
610 PRINTID;
611 printf("%d data errors detected\n", nerrs);
612 }
613
614 mpi_err = MPI_Barrier(MPI_COMM_WORLD);
615 return nerrs;
616 }
617
618 /*
619
620 Function: test_mpio_derived_dtype
621
622 Test Whether the Displacement of MPI derived datatype
623 (+ File_set_view + MPI_write)works or not on this MPI-IO package
624 and this platform.
625
626 1. Details for the test:
627 1) Create two derived datatypes with MPI_Type_hindexed:
628 datatype1:
629 count = 1, blocklens = 1, offsets = 0,
630 base type = MPI_BYTE(essentially a char)
631 datatype2:
632 count = 1, blocklens = 1, offsets = 1(byte),
633 base type = MPI_BYTE
634
635 2) Using these two derived datatypes,
636 Build another derived datatype with MPI_Type_struct:
637 advtype: derived from datatype1 and datatype2
638 advtype:
639 count = 2, blocklens[0] = 1, blocklens[1]=1,
640 offsets[0] = 0, offsets[1] = 1(byte),
641 bas_type[0]=datatype1,
642 bas_type[1] = datatype2;
643
644 3) Setting MPI file view with advtype
645 4) Writing 2 bytes 1 to 2 using MPI_File_write to a file
646 5) File content:
647 Suppose the fill value of the file is 0(most machines indeed do so)
648 and Fill value is embraced with "() in the following output:
649 Expected output should be:
650 1,0,2
651
652
653
654 However, at some platforms, for example, IBM AIX(at March 23rd, 2005):
655 the following values were obtained:
656 1,2,0
657
658 The problem is that the displacement of the second derived datatype(datatype2) which formed the final derived datatype(advtype)
659 has been put after the basic datatype(MPI_BYTE) of datatype2. This is a bug.
660
661
662 2. This test will verify whether the complicated derived datatype is working on
663 the current platform.
664
665 If this bug has been fixed in the previous not-working package, this test will issue a printf message to tell the developer to change
666 the configuration specific file of HDF5 so that we can change our configurationsetting to support collective IO for irregular selections.
667
668 If it turns out that the previous working MPI-IO package no longer works, this test will also issue a message to inform the corresponding failure so that
669 we can turn off collective IO support for irregular selections.
670 */
671
test_mpio_derived_dtype(char * filename)672 static int test_mpio_derived_dtype(char *filename) {
673
674 MPI_File fh;
675 char mpi_err_str[MPI_MAX_ERROR_STRING];
676 int mpi_err_strlen;
677 int mpi_err;
678 int i;
679 int nerrors = 0; /* number of errors */
680 MPI_Datatype etype,filetype;
681 MPI_Datatype adv_filetype,bas_filetype[2];
682 MPI_Datatype etypenew, filetypenew;
683 MPI_Offset disp;
684 MPI_Status Status;
685 MPI_Aint adv_disp[2];
686 MPI_Aint offsets[1];
687 int blocklens[1],adv_blocklens[2];
688 int count,outcount;
689 int retcode;
690
691 int mpi_rank,mpi_size;
692
693 char buf[3],outbuf[3] = {0};
694
695 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
696 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
697 retcode = 0;
698 for(i=0;i<3;i++)
699 buf[i] = i+1;
700
701
702 if ((mpi_err = MPI_File_open(MPI_COMM_WORLD, filename,
703 MPI_MODE_RDWR | MPI_MODE_CREATE,
704 MPI_INFO_NULL, &fh))
705 != MPI_SUCCESS){
706 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
707 printf("MPI_File_open failed (%s)\n", mpi_err_str);
708 return 1;
709 }
710
711 disp = 0;
712 etype = MPI_BYTE;
713
714 count = 1;
715 blocklens[0] = 1;
716 offsets[0] = 0;
717
718 if((mpi_err= MPI_Type_hindexed(count,blocklens,offsets,MPI_BYTE,&filetype))
719 != MPI_SUCCESS){
720 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
721 printf("MPI_Type_contiguous failed (%s)\n", mpi_err_str);
722 return 1;
723 }
724
725 if((mpi_err=MPI_Type_commit(&filetype))!=MPI_SUCCESS){
726 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
727 printf("MPI_Type_commit failed (%s)\n", mpi_err_str);
728 return 1;
729 }
730
731 count = 1;
732 blocklens[0]=1;
733 offsets[0] = 1;
734 if((mpi_err= MPI_Type_hindexed(count,blocklens,offsets,MPI_BYTE,&filetypenew))
735 != MPI_SUCCESS){
736 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
737 printf("MPI_Type_contiguous failed (%s)\n", mpi_err_str);
738 return 1;
739 }
740
741 if((mpi_err=MPI_Type_commit(&filetypenew))!=MPI_SUCCESS){
742 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
743 printf("MPI_Type_commit failed (%s)\n", mpi_err_str);
744 return 1;
745 }
746
747 outcount = 2;
748 adv_blocklens[0] = 1;
749 adv_blocklens[1] = 1;
750 adv_disp[0] = 0;
751 adv_disp[1] = 1;
752 bas_filetype[0] = filetype;
753 bas_filetype[1] = filetypenew;
754
755 if((mpi_err= MPI_Type_struct(outcount,adv_blocklens,adv_disp,bas_filetype,&adv_filetype))
756 != MPI_SUCCESS){
757 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
758 printf("MPI_Type_struct failed (%s)\n", mpi_err_str);
759 return 1;
760 }
761 if((mpi_err=MPI_Type_commit(&adv_filetype))!=MPI_SUCCESS){
762 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
763 printf("MPI_Type_commit failed (%s)\n", mpi_err_str);
764 return 1;
765 }
766
767
768 if((mpi_err = MPI_File_set_view(fh,disp,etype,adv_filetype,"native",MPI_INFO_NULL))!= MPI_SUCCESS){
769 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
770 printf("MPI_File_set_view failed (%s)\n", mpi_err_str);
771 return 1;
772 }
773
774 if((mpi_err = MPI_File_write(fh,buf,3,MPI_BYTE,&Status))!= MPI_SUCCESS){
775 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
776 printf("MPI_File_write failed (%s)\n", mpi_err_str);
777 return 1;
778 ;
779 }
780
781
782 if((mpi_err = MPI_File_close(&fh)) != MPI_SUCCESS){
783 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
784 printf("MPI_File_close failed (%s)\n", mpi_err_str);
785 return 1;
786 }
787
788
789 if((mpi_err = MPI_File_open(MPI_COMM_WORLD,filename,MPI_MODE_RDONLY,MPI_INFO_NULL,&fh)) != MPI_SUCCESS){
790 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
791 printf("MPI_File_open failed (%s)\n", mpi_err_str);
792 return 1;
793 }
794
795 if((mpi_err = MPI_File_set_view(fh,0,MPI_BYTE,MPI_BYTE,"native",MPI_INFO_NULL))!= MPI_SUCCESS){
796 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
797 printf("MPI_File_set_view failed (%s)\n", mpi_err_str);
798 return 1;
799 }
800 if((mpi_err = MPI_File_read(fh,outbuf,3,MPI_BYTE,&Status))!=MPI_SUCCESS){
801 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
802 printf("MPI_File_read failed (%s)\n", mpi_err_str);
803 return 1;
804 }
805
806 if(outbuf[2]==2) {
807 retcode = 0;
808 }
809 else {
810 /* if(mpi_rank == 0) {
811 printf("complicated derived datatype is NOT working at this platform\n");
812 printf("go back to hdf5/config and find the corresponding\n");
813 printf("configure-specific file and change ?????\n");
814 }
815 */
816 retcode = -1;
817 }
818
819 if((mpi_err = MPI_File_close(&fh)) != MPI_SUCCESS){
820 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
821 printf("MPI_File_close failed (%s)\n", mpi_err_str);
822 return 1;
823 }
824
825
826 mpi_err = MPI_Barrier(MPI_COMM_WORLD);
827 if(retcode == -1) {
828 if(mpi_rank == 0) {
829 printf("Complicated derived datatype is NOT working at this platform\n");
830 printf(" Please report to help@hdfgroup.org about this problem.\n");
831 }
832 retcode = 1;
833 }
834 return retcode;
835 }
836 /*
837
838 Function: test_mpio_special_collective
839
840 Test Whether collective IO is still working when more than one process
841 has no contribution to IO. To properly test this case, at least FOUR
842 processes are needed.
843
844 1. Details for the test:
845 1) Create one derived datatype with MPI_Type_hindexed:
846
847 2) Choosing at least two processes to contribute none for IO with
848 the buf size inside MPI_Write_at_all to 0.
849 3) Choosing at least two processes to have real contributions for IO.
850 4) Do collective IO.
851
852 2. This test will fail with the MPI-IO package that doesn't support this. For example,
853 mpich 1.2.6.
854
855 If this bug has been fixed in the previous not-working package, this test will issue a printf message to tell the developer to change
856 the configuration specific file of HDF5 so that we can change our configurationsetting to support special collective IO; currently only special collective IO.
857
858 If it turns out that the previous working MPI-IO package no longer works, this test will also issue a message to inform the corresponding failure so that
859 we can turn off the support for special collective IO; currently only special collective IO.
860 */
861
862 static int
test_mpio_special_collective(char * filename)863 test_mpio_special_collective(char *filename)
864 {
865 int mpi_size, mpi_rank;
866 MPI_File fh;
867 MPI_Datatype etype,buftype,filetype;
868 char mpi_err_str[MPI_MAX_ERROR_STRING];
869 int mpi_err_strlen;
870 int mpi_err;
871 char writedata[2*DIMSIZE];
872 char filerep[7] = "native";
873 int i;
874 int count,bufcount;
875 int blocklens[2];
876 MPI_Aint offsets[2];
877 MPI_Offset mpi_off = 0;
878 MPI_Status mpi_stat;
879 int retcode = 0;
880
881 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
882 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
883
884 /* create MPI data type */
885 etype = MPI_BYTE;
886 if(mpi_rank == 0 || mpi_rank == 1) {
887 count = DIMSIZE;
888 bufcount = 1;
889 } /* end if */
890 else {
891 count = 0;
892 bufcount = 0;
893 } /* end else */
894
895 blocklens[0] = count;
896 offsets[0] = mpi_rank*count;
897 blocklens[1] = count;
898 offsets[1] = (mpi_size+mpi_rank)*count;
899
900 if(count !=0) {
901 if((mpi_err = MPI_Type_hindexed(2,
902 blocklens,
903 offsets,
904 etype,
905 &filetype)) != MPI_SUCCESS) {
906 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
907 printf("MPI_Type_contiguous failed (%s)\n", mpi_err_str);
908 return 1;
909 } /* end if */
910
911 if((mpi_err = MPI_Type_commit(&filetype)) != MPI_SUCCESS) {
912 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
913 printf("MPI_Type_commit failed (%s)\n", mpi_err_str);
914 return 1;
915 } /* end if */
916
917 if((mpi_err = MPI_Type_hindexed(2,
918 blocklens,
919 offsets,
920 etype,
921 &buftype)) != MPI_SUCCESS) {
922 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
923 printf("MPI_Type_contiguous failed (%s)\n", mpi_err_str);
924 return 1;
925 } /* end if */
926
927 if((mpi_err = MPI_Type_commit(&buftype)) != MPI_SUCCESS) {
928 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
929 printf("MPI_Type_commit failed (%s)\n", mpi_err_str);
930 return 1;
931 } /* end if */
932 } /* end if */
933 else {
934 filetype = MPI_BYTE;
935 buftype = MPI_BYTE;
936 } /* end else */
937
938 /* Open a file */
939 if ((mpi_err = MPI_File_open(MPI_COMM_WORLD,
940 filename,
941 MPI_MODE_RDWR | MPI_MODE_CREATE,
942 MPI_INFO_NULL,
943 &fh)) != MPI_SUCCESS) {
944 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
945 printf("MPI_File_open failed (%s)\n", mpi_err_str);
946 return 1;
947 } /* end if */
948
949 /* each process writes some data */
950 for (i=0; i < 2*DIMSIZE; i++)
951 writedata[i] = (char)(mpi_rank*DIMSIZE + i);
952
953 /* Set the file view */
954 if((mpi_err = MPI_File_set_view(fh,
955 mpi_off,
956 MPI_BYTE,
957 filetype,
958 filerep,
959 MPI_INFO_NULL)) != MPI_SUCCESS) {
960 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
961 printf("MPI_File_set_view failed (%s)\n", mpi_err_str);
962 return 1;
963 } /* end if */
964
965 /* Collectively write into the file */
966 if ((mpi_err = MPI_File_write_at_all(fh,
967 mpi_off,
968 writedata,
969 bufcount,
970 buftype,
971 &mpi_stat)) != MPI_SUCCESS) {
972 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
973 printf("MPI_File_write_at offset(%ld), bytes (%d), failed (%s)\n",
974 (long) mpi_off, bufcount, mpi_err_str);
975 return 1;
976 } /* end if */
977
978 /* Close the file */
979 if ((mpi_err = MPI_File_close(&fh)) != MPI_SUCCESS) {
980 MPI_Error_string(mpi_err, mpi_err_str, &mpi_err_strlen);
981 printf("MPI_File_close failed. \n");
982 return 1;
983 } /* end if */
984
985 /* Perform a barrier */
986 mpi_err = MPI_Barrier(MPI_COMM_WORLD);
987 if(retcode != 0) {
988 if(mpi_rank == 0) {
989 printf("special collective IO is NOT working at this platform\n");
990 printf(" Please report to help@hdfgroup.org about this problem.\n");
991 } /* end if */
992 retcode = 1;
993 } /* end if */
994
995 return retcode;
996
997 } /* test_mpio_special_collective */
998
999 /*
1000 * parse the command line options
1001 */
1002 static int
parse_options(int argc,char ** argv)1003 parse_options(int argc, char **argv)
1004 {
1005 while (--argc){
1006 if (**(++argv) != '-'){
1007 break;
1008 }else{
1009 switch(*(*argv+1)){
1010 case 'v': if (*((*argv+1)+1))
1011 ParseTestVerbosity((*argv+1)+1);
1012 else
1013 SetTestVerbosity(VERBO_MED);
1014 break;
1015 case 'f': if (--argc < 1) {
1016 nerrors++;
1017 return(1);
1018 }
1019 if (**(++argv) == '-') {
1020 nerrors++;
1021 return(1);
1022 }
1023 paraprefix = *argv;
1024 break;
1025 case 'h': /* print help message--return with nerrors set */
1026 return(1);
1027 default: nerrors++;
1028 return(1);
1029 }
1030 }
1031 } /*while*/
1032
1033 /* compose the test filenames */
1034 {
1035 int i, n;
1036 hid_t plist;
1037
1038 plist = H5Pcreate (H5P_FILE_ACCESS);
1039 H5Pset_fapl_mpio(plist, MPI_COMM_WORLD, MPI_INFO_NULL);
1040 n = sizeof(FILENAME)/sizeof(FILENAME[0]) - 1; /* exclude the NULL */
1041
1042 for (i=0; i < n; i++)
1043 if (h5_fixname(FILENAME[i],plist,filenames[i],sizeof(filenames[i]))
1044 == NULL){
1045 printf("h5_fixname failed\n");
1046 nerrors++;
1047 return(1);
1048 }
1049 H5Pclose(plist);
1050 if (VERBOSE_MED){
1051 printf("Test filenames are:\n");
1052 for (i=0; i < n; i++)
1053 printf(" %s\n", filenames[i]);
1054 }
1055 }
1056
1057 return(0);
1058 }
1059
1060
1061 /*
1062 * Show command usage
1063 */
1064 static void
usage(void)1065 usage(void)
1066 {
1067 printf("Usage: t_mpi [-v<verbosity>] [-f <prefix>]\n");
1068 printf("\t-v<verbosity>\tset verbose level (0-9,l,m,h)\n");
1069 printf("\t-f <prefix>\tfilename prefix\n");
1070 printf("\n");
1071 }
1072
1073 /*
1074 * return the sum of all errors.
1075 */
1076 static int
errors_sum(int nerrs)1077 errors_sum(int nerrs)
1078 {
1079 int temp;
1080 MPI_Allreduce(&nerrs, &temp, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
1081 return(temp);
1082 }
1083
1084
1085 int
main(int argc,char ** argv)1086 main(int argc, char **argv)
1087 {
1088 int mpi_size, mpi_rank; /* mpi variables */
1089 int ret_code;
1090
1091 MPI_Init(&argc, &argv);
1092 MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
1093 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
1094
1095 /* Attempt to turn off atexit post processing so that in case errors
1096 * happen during the test and the process is aborted, it will not get
1097 * hang in the atexit post processing in which it may try to make MPI
1098 * calls. By then, MPI calls may not work.
1099 */
1100 if (H5dont_atexit() < 0){
1101 printf("Failed to turn off atexit processing. Continue.\n", mpi_rank);
1102 };
1103 H5open();
1104 if (parse_options(argc, argv) != 0){
1105 if (MAINPROCESS)
1106 usage();
1107 goto finish;
1108 }
1109
1110 if (MAINPROCESS){
1111 printf("===================================\n");
1112 printf("MPI functionality tests\n");
1113 printf("===================================\n");
1114 }
1115
1116 if (VERBOSE_MED)
1117 h5_show_hostname();
1118
1119 fapl = H5Pcreate (H5P_FILE_ACCESS);
1120 H5Pset_fapl_mpio(fapl, MPI_COMM_WORLD, MPI_INFO_NULL);
1121
1122 /* set alarm. */
1123 ALARM_ON;
1124
1125
1126 /*=======================================
1127 * MPIO 1 write Many read test
1128 *=======================================*/
1129 MPI_BANNER("MPIO 1 write Many read test...");
1130 ret_code = test_mpio_1wMr(filenames[0], USENONE);
1131 ret_code = errors_sum(ret_code);
1132 if (mpi_rank==0 && ret_code > 0){
1133 printf("***FAILED with %d total errors\n", ret_code);
1134 nerrors += ret_code;
1135 }
1136
1137 /* test atomicity and file sync in high verbose mode only */
1138 /* since they often hang when broken and PHDF5 does not use them. */
1139 if (VERBOSE_HI){
1140 MPI_BANNER("MPIO 1 write Many read test with atomicity...");
1141 ret_code = test_mpio_1wMr(filenames[0], USEATOM);
1142 ret_code = errors_sum(ret_code);
1143 if (mpi_rank==0 && ret_code > 0){
1144 printf("***FAILED with %d total errors\n", ret_code);
1145 nerrors += ret_code;
1146 }
1147
1148 MPI_BANNER("MPIO 1 write Many read test with file sync...");
1149 ret_code = test_mpio_1wMr(filenames[0], USEFSYNC);
1150 ret_code = errors_sum(ret_code);
1151 if (mpi_rank==0 && ret_code > 0){
1152 printf("***FAILED with %d total errors\n", ret_code);
1153 nerrors += ret_code;
1154 }
1155 }
1156
1157
1158 /*=======================================
1159 * MPIO MPIO File size range test
1160 *=======================================*/
1161 MPI_BANNER("MPIO File size range test...");
1162 #ifndef H5_HAVE_WIN32_API
1163 ret_code = test_mpio_gb_file(filenames[0]);
1164 ret_code = errors_sum(ret_code);
1165 if (mpi_rank==0 && ret_code > 0){
1166 printf("***FAILED with %d total errors\n", ret_code);
1167 nerrors += ret_code;
1168 }
1169 #else
1170 if (mpi_rank==0)
1171 printf(" will be skipped on Windows (JIRA HDDFV-8064)\n");
1172 #endif
1173
1174 /*=======================================
1175 * MPIO independent overlapping writes
1176 *=======================================*/
1177 MPI_BANNER("MPIO independent overlapping writes...");
1178 ret_code = test_mpio_overlap_writes(filenames[0]);
1179 ret_code = errors_sum(ret_code);
1180 if (mpi_rank==0 && ret_code > 0){
1181 printf("***FAILED with %d total errors\n", ret_code);
1182 nerrors += ret_code;
1183 }
1184
1185 /*=======================================
1186 * MPIO complicated derived datatype test
1187 *=======================================*/
1188 MPI_BANNER("MPIO complicated derived datatype test...");
1189 ret_code = test_mpio_derived_dtype(filenames[0]);
1190 ret_code = errors_sum(ret_code);
1191 if (mpi_rank==0 && ret_code > 0){
1192 printf("***FAILED with %d total errors\n", ret_code);
1193 nerrors += ret_code;
1194 }
1195
1196 /*=======================================
1197 * MPIO special collective IO test
1198 *=======================================*/
1199 if (mpi_size < 4) {
1200 MPI_BANNER("MPIO special collective io test SKIPPED.");
1201 if (mpi_rank == 0)
1202 printf("This test needs at least four processes to run.\n");
1203 ret_code = 0;
1204 goto sc_finish;
1205 } /* end if */
1206
1207 MPI_BANNER("MPIO special collective io test...");
1208 ret_code = test_mpio_special_collective(filenames[0]);
1209
1210 sc_finish:
1211 ret_code = errors_sum(ret_code);
1212 if (mpi_rank==0 && ret_code > 0){
1213 printf("***FAILED with %d total errors\n", ret_code);
1214 nerrors += ret_code;
1215 }
1216
1217
1218 finish:
1219 /* make sure all processes are finished before final report, cleanup
1220 * and exit.
1221 */
1222 MPI_Barrier(MPI_COMM_WORLD);
1223 if (MAINPROCESS){ /* only process 0 reports */
1224 printf("===================================\n");
1225 if (nerrors){
1226 printf("***MPI tests detected %d errors***\n", nerrors);
1227 }
1228 else{
1229 printf("MPI tests finished with no errors\n");
1230 }
1231 printf("===================================\n");
1232 }
1233
1234 /* turn off alarm */
1235 ALARM_OFF;
1236
1237 h5_clean_files(FILENAME, fapl);
1238 H5close();
1239
1240 /* MPI_Finalize must be called AFTER H5close which may use MPI calls */
1241 MPI_Finalize();
1242
1243 /* cannot just return (nerrors) because exit code is limited to 1byte */
1244 return(nerrors!=0);
1245 }
1246
1247