Using Argp with MPI-based applications
Argp is a great, great parser for command line options. When using it in MPI-based applications, there's a catch in that you want only one MPI rank to print --help information, usage warnings, error messages, etc. Otherwise, you get a whole mess of repeated, jumbled output as each MPI rank squawks about the same problem.
Here's a wrapper for Argp for use in MPI-based applications that solves just this nuisance:
#include <stdio.h> #include <unistd.h> #include "argp.h" /** * Call <a href="http://www.gnu.org/s/libc/manual/html_node/Argp.html" * >Argp</a>'s \c argp_parse in an MPI-friendly way. Processes * with nonzero rank will have their \c stdout and \c stderr redirected * to <tt>/dev/null</tt> during \c argp_parse. * * @param rank MPI rank of this process. Output from \c argp_parse * will only be observable from rank zero. * @param argp Per \c argp_parse semantics. * @param argc Per \c argp_parse semantics. * @param argv Per \c argp_parse semantics. * @param flags Per \c argp_parse semantics. * @param arg_index Per \c argp_parse semantics. * @param input Per \c argp_parse semantics. * * @return Per \c argp_parse semantics. */ error_t mpi_argp_parse(const int rank, const struct argp *argp, int argc, char **argv, unsigned flags, int *arg_index, void *input); error_t mpi_argp_parse(const int rank, const struct argp *argp, int argc, char **argv, unsigned flags, int *arg_index, void *input) { // Flush stdout, stderr if (fflush(stdout)) perror("mpi_argp_parse error flushing stdout prior to redirect"); if (fflush(stderr)) perror("mpi_argp_parse error flushing stderr prior to redirect"); // Save stdout, stderr so we may restore them later int stdout_copy, stderr_copy; if ((stdout_copy = dup(fileno(stdout))) < 0) perror("mpi_argp_parse error duplicating stdout"); if ((stderr_copy = dup(fileno(stderr))) < 0) perror("mpi_argp_parse error duplicating stderr"); // On non-root processes redirect stdout, stderr to /dev/null if (rank) { if (!freopen("/dev/null", "a", stdout)) perror("mpi_argp_parse error redirecting stdout"); if (!freopen("/dev/null", "a", stderr)) perror("mpi_argp_parse error redirecting stderr"); } // Invoke argp per http://www.gnu.org/s/libc/manual/html_node/Argp.html error_t retval = argp_parse(argp, argc, argv, flags, arg_index, input); // Flush stdout, stderr again if (fflush(stdout)) perror("mpi_argp_parse error flushing stdout after redirect"); if (fflush(stderr)) perror("mpi_argp_parse error flushing stderr after redirect"); // Restore stdout, stderr if (dup2(stdout_copy, fileno(stdout)) < 0) perror("mpi_argp_parse error reopening stdout"); if (dup2(stderr_copy, fileno(stderr)) < 0) perror("mpi_argp_parse error reopening stderr"); // Close saved versions of stdout, stderr if (close(stdout_copy)) perror("mpi_argp_parse error closing stdout_copy"); if (close(stderr_copy)) perror("mpi_argp_parse error closing stderr_copy"); // Clear any errors that may have occurred on stdout, stderr clearerr(stdout); clearerr(stderr); // Return what argp_parse returned return retval; }
2 comments:
Revisiting this pattern to use it in another context... The error reporting is broken for rank > 0 for line 64 onward as stderr has been reopened to /dev/null. Correcting it requires invoking a perror-like routine which writes to stderr_copy. Oops.
Using fprintf and strerror as indicated by http://stackoverflow.com/questions/10811290/how-use-perror-but-output-the-prompt-to-a-file seems to be the right way to fix that error reporting problem.
Post a Comment