203 строки
7.7 KiB
C
203 строки
7.7 KiB
C
/*
|
|
* Copyright (c) 2020 The University of Tennessee and The University
|
|
* of Tennessee Research Foundation. All rights
|
|
* reserved.
|
|
* $COPYRIGHT$
|
|
*
|
|
* Additional copyrights may follow
|
|
*
|
|
* $HEADER$
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "mpi.h"
|
|
|
|
#define print1(format...) if(0 == rank) printf(format)
|
|
|
|
int main_child(int argc, char *argv[]);
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rank=MPI_PROC_NULL, rc;
|
|
/* info_env and error handlers */
|
|
char init_errh_info[MPI_MAX_INFO_VAL+1]; int flag;
|
|
MPI_Errhandler errh;
|
|
/* error ops */
|
|
int eclass=MPI_SUCCESS;
|
|
char estr[MPI_MAX_ERROR_STRING]="NOT UPDATED"; int slen;
|
|
/* spawn params */
|
|
char* spawn_argv[3];
|
|
MPI_Info spawn_info;
|
|
int spawn_err[2] = {MPI_SUCCESS};
|
|
MPI_Comm icomm = MPI_COMM_NULL;
|
|
|
|
/* We will verify pre-init behavior in a spawnee to avoid aborting early in
|
|
* implementations with only partial support.
|
|
*/
|
|
if(argc > 1 && 0 == strcmp(argv[1], "preinit-error")) {
|
|
return main_child(argc, argv);
|
|
}
|
|
|
|
/* Lets assume everything goes fine until we inject our own errors, no
|
|
* error checking */
|
|
MPI_Init(&argc, &argv);
|
|
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
|
|
|
print1(
|
|
"# This test checks compliance with MPI-4 initial error handler.\n"
|
|
"# This test assumes that the command line parameter '-initial-errhandler mpi_errors_return'\n"
|
|
"# is passed to 'mpiexec', in which case, a compliant implementation will:\n"
|
|
"# * Set the MPI_INFO_ENV key to the requested error handler.\n"
|
|
"# * The requested handler is set on the predefined communicators MPI_COMM_SELF, MPI_COMM_WORLD,\n"
|
|
"# and the communicator returned from MPI_COMM_GET_PARENT.\n"
|
|
"# In a high quality implementation:\n"
|
|
"# * Errors reported from calls during, before, and after MPI_INIT and MPI_FINALIZE also invoke the\n"
|
|
"# initial error handler.\n"
|
|
"# * MPI_ERROR_STRING and MPI_ERROR_CLASS provide useful information before/after MPI_INIT and\n"
|
|
"# MPI_FINALIZE respectively.\n\n");
|
|
|
|
print1("MPI_INFO_ENV for key 'mpi_initial_errhandler'\n");
|
|
MPI_Info_get(MPI_INFO_ENV, "mpi_initial_errhandler", MPI_MAX_INFO_VAL, init_errh_info, &flag);
|
|
if(flag) {
|
|
print1(" MPI-4 COMPLIANT:\tMPI_INFO_ENV value set for key 'mpi_initial_errhandler' = %s\n\n", init_errh_info);
|
|
}
|
|
else {
|
|
print1(" NOT MPI-4 COMPLIANT:\tMPI_INFO_ENV has no value set for key 'mpi_initial_errhandler'\n\n");
|
|
}
|
|
|
|
print1("MPI_COMM_GET_ERRHANDLER:\n");
|
|
MPI_Comm_get_errhandler(MPI_COMM_SELF, &errh);
|
|
if(MPI_ERRORS_RETURN == errh) {
|
|
print1(" MPI-4 COMPLIANT:\tMPI_COMM_SELF error handler set to MPI_ERRORS_RETURN.\n\n");
|
|
}
|
|
else
|
|
if(MPI_ERRORS_ABORT == errh) {
|
|
print1(" UNEXPECTED:\tMPI_COMM_SELF error handler set to MPI_ERRORS_ABORT.\n\n");
|
|
}
|
|
else
|
|
if(MPI_ERRORS_ARE_FATAL == errh) {
|
|
print1(" NOT MPI-4 COMPLIANT:\tMPI_COMM_SELF error handler set to MPI_ERRORS_ARE_FATAL.\n\n");
|
|
}
|
|
else {
|
|
print1(" UNEXPECTED:\tMPI_COMM_SELF error handler is not one of the predefined ones.\n\n");
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
MPI_Info_create(&spawn_info);
|
|
MPI_Info_set(spawn_info, "mpi_initial_errhandler", "mpi_errors_return");
|
|
spawn_argv[0] = argv[0];
|
|
spawn_argv[1] = "preinit-error";
|
|
spawn_argv[2] = NULL;
|
|
MPI_Comm_spawn(argv[0], &spawn_argv[1], 1, spawn_info, 0, MPI_COMM_WORLD, &icomm, spawn_err);
|
|
|
|
/* wait for the spawnee completion before testing post-finalize error
|
|
* handling */
|
|
MPI_Barrier(icomm);
|
|
MPI_Comm_disconnect(&icomm);
|
|
sleep(2);
|
|
|
|
/* set error handler to fatal before FINALIZE */
|
|
rc = MPI_Comm_set_errhandler(MPI_COMM_SELF, MPI_ERRORS_ARE_FATAL);
|
|
if(MPI_SUCCESS != rc) {
|
|
MPI_Error_string(rc, estr, &slen);
|
|
fprintf(stderr, " UNEXPECTED: An error occured during MPI_COMM_SETERRHANDLER(SELF) rc=%d: %s\n", rc, estr);
|
|
return rc;
|
|
}
|
|
/* FINALIZE should force reversion to the initial errhandler, so we need to
|
|
* check again (though we did not insert errors so all should go smooth). */
|
|
rc = MPI_Finalize();
|
|
if(MPI_SUCCESS != rc) {
|
|
MPI_Error_string(rc, estr, &slen);
|
|
fprintf(stderr, " UNEXPECTED: An error occured during MPI_FINALIZE rc=%d: %s\n", rc, estr);
|
|
return rc;
|
|
}
|
|
|
|
printf("Post-finalize MPI_ERROR_STRING call:\n");
|
|
rc = MPI_Error_string(MPI_ERR_WIN, estr, &slen);
|
|
if(MPI_SUCCESS != rc) {
|
|
fprintf(stderr, " NOT MPI-4 COMPLIANT:\tpost-finalize MPI_ERROR_STRING returned %d (expected MPI_SUCCESS)\n", rc);
|
|
}
|
|
else if(0 == strcmp(estr, "NOT UPDATED")) {
|
|
fprintf(stderr, " NOT MPI-4 COMPLIANT:\tpost-finalize MPI_ERROR_STRING did not set a valid string.\n");
|
|
}
|
|
else {
|
|
/* We can't further check if the error string makes sense; In any
|
|
* case, any string is compliant, even low-quality non-informative
|
|
* generic strings. So we just print it. */
|
|
printf(" MPI-4 COMPLIANT:\tpost-finalize MPI_ERROR_STRING for MPI_ERR_WIN: %s\n", estr);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main_child(int argc, char *argv[]) {
|
|
int rank=0, rc;
|
|
MPI_Comm icomm=MPI_COMM_NULL;
|
|
int eclass=MPI_SUCCESS;
|
|
char estr[MPI_MAX_ERROR_STRING]="NOT UPDATED"; int slen;
|
|
|
|
/* ERROR_CLASS and ERROR_STRING are callable before MPI_INIT */
|
|
|
|
printf("Pre-init MPI_ERROR_CLASS call:\n");
|
|
rc = MPI_Error_class(MPI_ERR_WIN, &eclass);
|
|
if(MPI_SUCCESS != rc) {
|
|
fprintf(stderr, " NOT MPI-4 COMPLIANT:\tpre-init MPI_ERROR_CLASS returned %d (expected MPI_SUCCESS)\n", rc);
|
|
}
|
|
else if(MPI_ERR_WIN != eclass) {
|
|
fprintf(stderr, " NOT MPI-4 COMPLIANT:\tpre-init MPI_ERROR_CLASS set eclass=%d (expected %d)\n", eclass, MPI_ERR_WIN);
|
|
}
|
|
else {
|
|
printf(" MPI-4 COMPLIANT:\tPre-init MPI_ERROR_CLASS\n");
|
|
}
|
|
|
|
print1("Pre-init MPI_ERROR_STRING call:\n");
|
|
rc = MPI_Error_string(MPI_ERR_WIN, estr, &slen);
|
|
if(MPI_SUCCESS != rc) {
|
|
fprintf(stderr, " NOT MPI-4 COMPLIANT:\tpre-init MPI_ERROR_STRING returned %d (expected MPI_SUCCESS)\n", rc);
|
|
}
|
|
else if(0 == strcmp(estr, "NOT UPDATED")) {
|
|
fprintf(stderr, " NOT MPI-4 COMPLIANT:\tpre-init MPI_ERROR_STRING did not set a valid string.\n");
|
|
}
|
|
else {
|
|
/* We can't further check if the error string makes sense; In any
|
|
* case, any string is compliant, even low-quality non-informative
|
|
* generic strings. So we just print it. */
|
|
printf(" MPI-4 COMPLIANT:\tPre-init MPI_ERROR_STRING for MPI_ERR_WIN: %s\n", estr);
|
|
}
|
|
|
|
printf("Pre-init error in a call: compliant if it does not abort\n");
|
|
rc = MPI_Error_class(MPI_ERR_LASTCODE+1, &eclass);
|
|
eclass = rc;
|
|
rc = MPI_Error_string(eclass, estr, &slen);
|
|
if(MPI_SUCCESS != rc) {
|
|
printf(" MPI-4 COMPLIANT:\tPre-init MPI_ERROR_CLASS with erroneous arguments returned (LOW QUALITY: error code=%d caused error %d in MPI_ERROR_STRING).\n", eclass, rc);
|
|
}
|
|
else {
|
|
printf(" MPI-4 COMPLIANT:\tPre-init MPI_ERROR_STRING for non-existing code returned %d: %s\n", eclass, estr);
|
|
}
|
|
|
|
printf("Initializing MPI and setting error handlers on predefined communicators.\n");
|
|
rc = MPI_Init(&argc, &argv);
|
|
if(MPI_SUCCESS != rc) {
|
|
MPI_Error_string(rc, estr, &slen);
|
|
fprintf(stderr, " UNEXPECTED: An error occured during MPI_INIT rc=%d: %s\n", rc, estr);
|
|
return rc;
|
|
}
|
|
|
|
/* sync-up with parent */
|
|
MPI_Comm_get_parent(&icomm);
|
|
rc = MPI_Comm_set_errhandler(icomm, MPI_ERRORS_ARE_FATAL);
|
|
if(MPI_SUCCESS != rc) {
|
|
MPI_Error_string(rc, estr, &slen);
|
|
fprintf(stderr, " UNEXPECTED: An error occured during MPI_COMM_SETERRHANDLER(PARENT) rc=%d: %s\n", rc, estr);
|
|
return rc;
|
|
}
|
|
MPI_Barrier(icomm);
|
|
MPI_Comm_disconnect(&icomm);
|
|
|
|
MPI_Finalize();
|
|
return 0;
|
|
}
|