diff --git a/environ-mgmt/Makefile.am b/environ-mgmt/Makefile.am new file mode 100644 index 0000000..1b20eb3 --- /dev/null +++ b/environ-mgmt/Makefile.am @@ -0,0 +1,8 @@ +# +# Copyright (c) 2020 Cisco Systems, Inc. All rights reserved +# Copyright (c) 2025 UT-Battelle, LLC. All rights reserved +# +# $COPYRIGHT$ +# + +SUBDIRS = src diff --git a/environ-mgmt/README.md b/environ-mgmt/README.md new file mode 100644 index 0000000..d4a7464 --- /dev/null +++ b/environ-mgmt/README.md @@ -0,0 +1,63 @@ +Environ Management Tests +------------------------ + +Tests for items in the "MPI Environmental Management" chapter. + +These are being created in the ompi-tests-public repository +to ensure they are easy to access. + +Using autotools to detect if we have the MPI-4.1 remove error code +functionality, otherwise skips. + +Usage +----- + - Ensure MPI `mpicc` in `PATH` + - Run autogen/configure/make to build test + + ``` + cd environ-mgmt/ + ./autogen.sh && ./configure && make + ``` + + - Run test(s) + + ``` + mpirun -np 1 ./src/test_add_del_err_codes + ``` + +Example Output +-------------- + + - On MPI 3.x + ``` + laptop:$ mpirun -np 1 ./src/test_add_del_err_codes + TEST: Success creating error class/code/string (last=92, newlast=94) + ==== Adds done ==== + ==== Remove estring ==== + Warning: MPI_Remove_error_xxx code/class/string NOT available! + ==== Remove ecode ==== + Warning: MPI_Remove_error_xxx code/class/string NOT available! + ==== Remove eclass ==== + Warning: MPI_Remove_error_xxx code/class/string NOT available! + DONE: Success + laptop$ echo $? + 0 + laptop$ + ``` + + - On MPI 4.1 or later + ``` + laptop:$ mpirun -np 1 ./src/test_add_del_err_codes + TEST: Success creating error class/code/string (last=92, newlast=94) + ==== Adds done ==== + ==== Remove estring ==== + ==== Remove ecode ==== + TEST: Success reomved error code (oldlast=94, newlast=93) + ==== Remove eclass ==== + TEST: Success reomved error class (oldlast=93, newlast=92) + DONE: Success + laptop$ echo $? + 0 + laptop$ + ``` + diff --git a/environ-mgmt/autogen.sh b/environ-mgmt/autogen.sh new file mode 100755 index 0000000..a28bc75 --- /dev/null +++ b/environ-mgmt/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +autoreconf --install + diff --git a/environ-mgmt/configure.ac b/environ-mgmt/configure.ac new file mode 100644 index 0000000..cb0408b --- /dev/null +++ b/environ-mgmt/configure.ac @@ -0,0 +1,124 @@ +# -*- shell-script -*- +# +# Copyright (c) 2012-2020 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2025 UT-Battelle, LLC. All rights reserved. +# +# $COPYRIGHT$ +# + +dnl +dnl Init autoconf +dnl + +AC_PREREQ([2.67]) +AC_INIT([mpi-environmgmt-test], [1.0], [http://www.open-mpi.org]) +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_MACRO_DIR([config]) +AC_CONFIG_SRCDIR([.]) + +echo "Configuring Environmental Management test" + +AM_INIT_AUTOMAKE([1.11 foreign -Wall -Werror]) + +# If Automake supports silent rules, enable them. +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AH_TOP([/* -*- c -*- + * + * Environmental Management test suite configuation header file. + * See the top-level LICENSE file for license and copyright + * information. + */ + +#ifndef MPI_ENVIRONMGMT_TEST_CONFIG_H +#define MPI_ENVIRONMGMT_TEST_CONFIG_H +]) +AH_BOTTOM([#endif /* MPI_ENVIRONMGMT_TEST_CONFIG_H */]) + +dnl +dnl Make automake clean emacs ~ files for "make clean" +dnl + +CLEANFILES="*~" +AC_SUBST(CLEANFILES) + +dnl +dnl Get various programs +dnl Bias towards mpicc/mpic++/mpif77 +dnl C compiler +dnl + +if test "$CC" != ""; then + BASE="`basename $CC`" +else + BASE= +fi +if test "$BASE" = "" -o "$BASE" = "." -o "$BASE" = "cc" -o \ + "$BASE" = "gcc" -o "$BASE" = "xlc" -o "$BASE" = "pgcc" -o \ + "$BASE" = "icc"; then + AC_CHECK_PROG(HAVE_MPICC, mpicc, yes, no) + if test "$HAVE_MPICC" = "yes"; then + CC=mpicc + export CC + fi +fi + +CFLAGS_save=$CFLAGS +AC_PROG_CC +CFLAGS=$CFLAGS_save + +dnl +dnl Because these are meant to be used for debugging, after all +dnl + +if test -z "$CFLAGS"; then + CFLAGS="-g" +fi + +dnl +dnl Ensure that we can compile and link a C MPI program +dnl + +AC_LANG_PUSH([C]) +AC_CHECK_HEADERS(mpi.h) + +AC_MSG_CHECKING([if linking MPI program works]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include +]], + [[MPI_Comm a = MPI_COMM_WORLD]])], + [AC_MSG_RESULT([yes])], + [AC_MSG_RESULT([no]) + AC_MSG_WARN([Simple MPI program fails to link]) + AC_MSG_ERROR([Cannot continue]) + ]) + +AC_CHECK_LIB([mpi], [MPI_Add_error_code], + [AC_DEFINE([HAVE_MPI_ADD_ERROR_CODE], [1], [Define if have MPI_Add_error_code])], + [AC_MSG_WARN([MPI_Add_error_code not found; disable related features])]) + + +AC_CHECK_LIB([mpi], [MPI_Remove_error_code], + [AC_DEFINE([HAVE_MPI_REMOVE_ERROR_CODE], [1], [Define if have MPI_Remove_error_code])], + [AC_MSG_WARN([MPI_Remove_error_code not found; disable related features])]) + +AC_CHECK_LIB([mpi], [MPI_Remove_error_class], + [AC_DEFINE([HAVE_MPI_REMOVE_ERROR_CLASS], [1], [Define if have MPI_Remove_error_class])], + [AC_MSG_WARN([MPI_Remove_error_class not found; disable related features])]) + +AC_CHECK_LIB([mpi], [MPI_Remove_error_string], + [AC_DEFINE([HAVE_MPI_REMOVE_ERROR_STRING], [1], [Define if have MPI_Remove_error_string])], + [AC_MSG_WARN([MPI_Remove_error_string not found; disable related features])]) + +AC_SUBST([MPI_LIBS]) + +AC_LANG_POP([C]) + +dnl +dnl Party on +dnl + +AC_CONFIG_FILES([ + Makefile + src/Makefile +]) +AC_OUTPUT diff --git a/environ-mgmt/src/Makefile.am b/environ-mgmt/src/Makefile.am new file mode 100644 index 0000000..7a8a069 --- /dev/null +++ b/environ-mgmt/src/Makefile.am @@ -0,0 +1,12 @@ +# +# Copyright (c) 2020 Cisco Systems, Inc. All rights reserved +# Copyright (c) 2025 UT-Battelle, LLC. All rights reserved +# +# +# $COPYRIGHT$ +# + +noinst_PROGRAMS = test_add_del_err_codes + +test_add_del_err_codes_SOURCES = \ + test_add_del_err_codes.c diff --git a/environ-mgmt/src/test_add_del_err_codes.c b/environ-mgmt/src/test_add_del_err_codes.c new file mode 100644 index 0000000..c78b1dc --- /dev/null +++ b/environ-mgmt/src/test_add_del_err_codes.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2025 UT-Battelle, LLC. All rights reserved. + * + * Tests for MPI_LASTUSEDCODE, MPI_Add_error_{class,code,string}, and + * MPI_Remove_error{class,code,string}. + * + * File: test_add_del_err_codes.c + * + * Referenced examples online and in ompi-tests: + * - "ompi-tests/random/add_error_class.c" + * - example from Lisandro Dalcin + * https://www.open-mpi.org/community/lists/devel/2014/04/14578.php + */ +#include +#include + +#include "mpi.h" + +#define SUCCESS (0) +#define FAILURE (-1) +#define SKIPTEST (-2) + +#define CHECK_RC(_rc,_msg) do {\ + if (_rc != MPI_SUCCESS) { \ + fprintf(stderr, "[%s:%d] Error: %s failed (rc=%d)\n", __FUNCTION__, __LINE__, _msg, _rc); \ + exit(1); \ + } \ + } while(0) + +int get_lastused(MPI_Comm comm); +int do_add_error(MPI_Comm comm, int *eclass, int *ecode, char *estr); +int do_del_error_string(MPI_Comm comm, int eclass, int ecode, char *estr); +int do_del_error_code(MPI_Comm comm, int eclass, int ecode, char *estr); +int do_del_error_class(MPI_Comm comm, int eclass, int ecode, char *estr); + +int get_lastused(MPI_Comm comm) +{ + int *last = NULL; + int flag = 0; + + CHECK_RC( MPI_Comm_get_attr(comm, MPI_LASTUSEDCODE, &last, &flag), + "MPI_Comm_get_attr"); + + if (flag == 0) + return (-1); /* no key found */ + else + return (*last); +} + +int do_add_error(MPI_Comm comm, int *eclass, int *ecode, char *estr) +{ + int ret = SUCCESS; + +#ifdef HAVE_MPI_ADD_ERROR_CODE + int last = 0, newlast = 0; + last = get_lastused(MPI_COMM_WORLD); + + CHECK_RC( MPI_Add_error_class(eclass), "MPI_Add_error_class"); + CHECK_RC( MPI_Add_error_code(*eclass, ecode), "MPI_Add_error_code"); + CHECK_RC( MPI_Add_error_string(*ecode, estr), "MPI_Add_error_string"); + + newlast = get_lastused(MPI_COMM_WORLD); + + if (newlast > last) { + printf("TEST: Success creating error class/code/string (last=%d, newlast=%d)\n", last, newlast); + ret = SUCCESS; + } else { + printf("Error: MPI_Add_error_xxx failed LastUsedCode not increased (last=%d, new=%d)\n", last, newlast); + ret = FAILURE; + } + +#else + printf("Warning: MPI_Add_error_xxx code/class/string NOT available!\n"); + ret = SKIPTEST; +#endif /* HAVE_MPI_ADD_ERROR_CODE */ + + return(ret); +} + + +int do_del_error_string(MPI_Comm comm, int eclass, int ecode, char *estr) +{ + int ret = SUCCESS; + +#ifdef HAVE_MPI_REMOVE_ERROR_CODE + CHECK_RC( MPI_Remove_error_string(ecode), "MPI_Remove_error_string"); +#else + /* We should have MPI_Remove_error_xxx with MPI >= 4.1 */ + printf("Warning: MPI_Remove_error_string NOT available!\n"); + ret = SKIPTEST; +#endif /* HAVE_MPI_REMOVE_ERROR_CODE */ + + return(ret); +} + +int do_del_error_code(MPI_Comm comm, int eclass, int ecode, char *estr) +{ + int ret = SUCCESS; + +#ifdef HAVE_MPI_REMOVE_ERROR_CODE + int last = 0, newlast = 0; + last = get_lastused(MPI_COMM_WORLD); + + CHECK_RC( MPI_Remove_error_code(ecode), "MPI_Remove_error_code"); + + newlast = get_lastused(MPI_COMM_WORLD); + + if (newlast < last) { + printf("TEST: Success removed error code (oldlast=%d, newlast=%d)\n", last, newlast); + ret = SUCCESS; + } else { + printf("Error: MPI_Remove_error_code failed LastUsedCode not decreased (last=%d, new=%d)\n", last, newlast); + ret = FAILURE; + } + +#else + /* We should have MPI_Remove_error_xxx with MPI >= 4.1 */ + printf("Warning: MPI_Remove_error_code NOT available!\n"); + ret = SKIPTEST; +#endif /* HAVE_MPI_REMOVE_ERROR_CODE */ + + return(ret); +} + +int do_del_error_class(MPI_Comm comm, int eclass, int ecode, char *estr) +{ + int ret = SUCCESS; + +#ifdef HAVE_MPI_REMOVE_ERROR_CODE + int last = 0, newlast = 0; + last = get_lastused(MPI_COMM_WORLD); + + CHECK_RC( MPI_Remove_error_class(eclass), "MPI_Remove_error_class"); + + newlast = get_lastused(MPI_COMM_WORLD); + + if (newlast < last) { + printf("TEST: Success removed error class (oldlast=%d, newlast=%d)\n", last, newlast); + ret = SUCCESS; + } else { + printf("Error: MPI_Remove_error_class failed LastUsedCode not decreased (last=%d, new=%d)\n", last, newlast); + ret = FAILURE; + } + +#else + /* We should have MPI_Remove_error_xxx with MPI >= 4.1 */ + printf("Warning: MPI_Remove_error_class NOT available!\n"); + ret = SKIPTEST; +#endif /* HAVE_MPI_REMOVE_ERROR_CODE */ + + return(ret); +} + + +int main (int argc, char **argv) +{ + int rc, rank=0, size; + int retval = EXIT_SUCCESS; + int eclass, ecode; + char *estr = "My Dummy Error String"; + + CHECK_RC( MPI_Init(&argc, &argv), "MPI_Init"); + CHECK_RC( MPI_Comm_rank(MPI_COMM_WORLD, &rank), "MPI_Comm_rank"); + CHECK_RC( MPI_Comm_size(MPI_COMM_WORLD, &size), "MPI_Comm_size"); + + rc = do_add_error(MPI_COMM_WORLD, &eclass, &ecode, estr); + if ((SUCCESS != rc) && (SKIPTEST != rc)) { + printf("Error: Failed during do_add_error testing (rc=%d)\n", rc); + retval = EXIT_FAILURE; + goto fini; + } + + printf("==== Adds done ====\n"); + + printf("==== Remove estring ====\n"); + rc = do_del_error_string(MPI_COMM_WORLD, eclass, ecode, estr); + if ((SUCCESS != rc) && (SKIPTEST != rc)) { + printf("Error: Failed during do_del_error_string testing (rc=%d)\n", rc); + retval = EXIT_FAILURE; + goto fini; + } + + printf("==== Remove ecode ====\n"); + rc = do_del_error_code(MPI_COMM_WORLD, eclass, ecode, estr); + if ((SUCCESS != rc) && (SKIPTEST != rc)) { + printf("Error: Failed during do_del_error_code testing (rc=%d)\n", rc); + retval = EXIT_FAILURE; + goto fini; + } + + printf("==== Remove eclass ====\n"); + rc = do_del_error_class(MPI_COMM_WORLD, eclass, ecode, estr); + if ((SUCCESS != rc) && (SKIPTEST != rc)) { + printf("Error: Failed during do_del_error_class testing (rc=%d)\n", rc); + retval = EXIT_FAILURE; + goto fini; + } + +fini: + CHECK_RC( MPI_Finalize(), "MPI_Finalize"); + + if (rank == 0) { + if (retval == EXIT_SUCCESS) { + printf("DONE: Success\n"); + } else { + printf("DONE: Failure\n"); + } + } + + return(retval); +} +