Hi all,

I'm developing on Open MPI 1.4.5-ubuntu2 on Ubuntu 13.10 (so, Ubuntu's
packaged Open MPI) at the moment.

I'd like to pass environment variables to processes started via
MPI_Comm_spawn.  Unfortunately, the MPI 3.0 standard (at least) does
not seem to specify a way to do this; thus I have been searching for
implementation-specific ways to accomplish my task.

I have tried setting the environment variable using the POSIX setenv(3)
call, but it seems that Open MPI comm-spawn'd processes do not inherit
environment variables.  See the attached 2 C99 programs; one prints
out the environment it receives, and one sets the MEANING_OF_LIFE
environment variable, spawns the previous 'env printing' program, and
exits.  I run via:

  $ env -i HOME=/home/tfogal \
  PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin \
  mpirun -x TJFVAR=testing -n 5 ./mpienv ./envpar

and expect (well, hope) to find the MEANING_OF_LIFE in 'envpar's
output.  I do see TJFVAR, but the MEANING_OF_LIFE sadly does not
propagate.  Perhaps I am asking the wrong question...

I found another MPI implementation which allowed passing such
information via the MPI_Info argument, however I could find no
documentation of similar functionality in Open MPI.

Is there a way to accomplish what I'm looking for?  I could even be
convinced to hack source, but a starting pointer would be appreciated.

Thanks,

-tom

#define _POSIX_C_SOURCE 200112L 
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>

#define ROOT(stmt) \
  do { \
    if(rank() == 0) { stmt; } \
  } while(0)

static size_t rank();
static size_t size();
static void rebuild_args(size_t argc, char* argv[], char** cmd, char* subv[]);

int
main(int argc, char* argv[])
{
  MPI_Init(&argc, &argv);
  if(rank() == 0 && argc < 2) {
    fprintf(stderr, "Need at least one argument: the binary to run.\n");
    MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
  }
  ROOT(printf("Running on %zu procs.\n", size()));

  /* MPI (annoyingly) displaces the argument list by one, so rebuild it. */
  char* subv[argc]; memset(subv, 0, sizeof(char*)*argc);
  char* command;
  assert(argc > 0);
  rebuild_args((size_t)argc, argv, &command, subv);

  MPI_Comm intercomm; /* we don't need, but MPI requires. */
  int errors[size()];
  if(setenv("MEANING_OF_EVERYTHING", "42", 1) != 0) {
    fprintf(stderr, "[%zu] failed setting LD_PRELOAD env var.\n", rank());
  }
  int spawn = MPI_Comm_spawn(command, subv, (int)size(), MPI_INFO_NULL, 0,
                             MPI_COMM_WORLD, &intercomm, errors);
  if(spawn != MPI_SUCCESS) {
    fprintf(stderr, "[%zu] spawn error: %d\n", rank(), spawn);
  }
  for(size_t i=0; rank()==0 && i < size(); ++i) {
    if(errors[i] != MPI_SUCCESS) {
      printf("process %zu error: %d\n", i, errors[i]);
    }
  }

  MPI_Finalize();
  return 0;
}

static size_t
rank()
{
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  return (size_t)rank;
}

static size_t
size()
{
  int size;
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  return (size_t)size;
}

static void
rebuild_args(size_t argc, char* argv[], char** cmd, char* subv[])
{
  /* argv[0] is the name of this program.
   * argv[1] is the name of the program the user wanted to run, "child"
   * argv[x] for x > 1 are the arguments of "child". */
  for(size_t i=2; i < argc; ++i) {
    subv[i-2] = argv[i];
  }
  *cmd = argv[1];
}
#include <stdio.h>
#include <mpi.h>

static size_t
rank()
{
  int rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  return (size_t)rank;
}

extern char** environ;

int
main(int argc, char* argv[])
{
  MPI_Init(&argc, &argv);
  for(char** ev=environ; rank() == 0 && *ev; ++ev) {
    printf("env: %s\n", *ev);
  }
  MPI_Finalize();
}

Reply via email to