Ejemplo n.º 1
0
/* Get the default algorithm for a given (geometery, collective) pair.
   This will be the first "always works" algorithm unless user provides an override.
*/
extern void
gasnetc_dflt_coll_alg(pami_geometry_t geom, pami_xfer_type_t op, pami_algorithm_t *alg_p) {
  static int print_once[PAMI_XFER_COUNT]; /* static var must initially be all zeros */
  pami_result_t rc;
  size_t counts[2];
  pami_algorithm_t *algorithms;
  pami_metadata_t *metadata;
  const char *envvar, *envval, *dfltval;
  int alg, fullcount;

  gasneti_assert(op >= 0);
  gasneti_assert(op < PAMI_XFER_COUNT);

  rc = PAMI_Geometry_algorithms_num(geom, op, counts);
  GASNETC_PAMI_CHECK(rc, "calling PAMI_Geometry_algorithms_num()");
  fullcount = counts[0] + counts[1];

  /* Space for algorithms and metadata */
  algorithms = alloca(fullcount * sizeof(pami_algorithm_t));
  metadata   = alloca(fullcount * sizeof(pami_metadata_t));

  rc = PAMI_Geometry_algorithms_query(geom, op,
                                      algorithms, metadata, counts[0],
                                      algorithms+counts[0], metadata+counts[0], counts[1]);
  GASNETC_PAMI_CHECK(rc, "calling PAMI_Geometry_algorithms_query()");

  /* Process environment and defaults: */
  switch(op) { /* please keep alphabetical */
  /* Used for blocking gasnet exchange: */
  case PAMI_XFER_ALLTOALL:
    envvar = "GASNET_PAMI_ALLTOALL_ALG";
  #if GASNETI_ARCH_BGQ
    dfltval = "I0:M2MComposite:MU:MU"; /* Best on BG/Q by a large margin */
  #else
    dfltval = "I0:Ring:"; /* Uniformly 2nd place (out of 3) on PERCS */
  #endif
    break;

  /* Used for blocking gasnet exchange w/ multiple images: */
  case PAMI_XFER_ALLTOALLV_INT:
    envvar = "GASNET_PAMI_ALLTOALLV_INT_ALG";
  #if GASNETI_ARCH_BGQ
    dfltval = "I0:M2MComposite:MU:MU"; /* Best on BG/Q by a large margin */
  #else
    dfltval = "I0:M2MComposite:"; /* Best on PERCS for all but smallest len (where it is close) */
  #endif
    break;

  /* Used for blocking gasnet gatherall and gasnetc_bootstrapExchange(): */
  case PAMI_XFER_ALLGATHER:
    envvar = "GASNET_PAMI_ALLGATHER_ALG";
  #if GASNETI_ARCH_BGQ && 0 /* TODO: split choice based on size */
    dfltval = "I0:RectangleDput:"; /* Uniformly best (or very near) for LARGE case only... */
    /* .. but only available for "rectangular" jobs. */
    alg = gasnetc_find_alg(dfltval, metadata, counts[0]);
    if (alg < counts[0]) break; /* Otherwise fall through */
  #endif
    dfltval = "I0:Binomial:"; /* Uniformly 2nd place (out of 3) on PERCS, uniformly "OK" on BG/Q */
    break;

  /* Used for blocking gasnet gatherall w/ multiple images: */
  case PAMI_XFER_ALLGATHERV_INT:
    envvar = "GASNET_PAMI_ALLGATHERV_INT_ALG";
  #if GASNETI_ARCH_BGQ && 0 /* TODO: split choice based on size */
    dfltval = "I0:RectangleDput:"; /* Uniformly best for small to moderate cases only ... */
    /* .. but only available for "rectangular" jobs. */
    alg = gasnetc_find_alg(dfltval, metadata, counts[0]);
    if (alg < counts[0]) break; /* Otherwise fall through */
  #endif
    dfltval = NULL; /* Only one other option available on systems I've tested -PHH */
    break;

  /* Used for exitcode reduction and "PAMIALLREDUCE" barrier: */
  case PAMI_XFER_ALLREDUCE:
    envvar = "GASNET_PAMI_ALLREDUCE_ALG";
  #if GASNETI_ARCH_BGQ
    dfltval = "I0:Binomial:-:ShortMU"; /* great when available */
    alg = gasnetc_find_alg(dfltval, metadata, fullcount);
    if (alg < fullcount) {
      /* make sure PAMI-allreduce barrier and exitcode reduction will "fit" */
      pami_metadata_t *md = &metadata[alg];
      if ((!md->check_correct.values.rangeminmax  || md->range_lo <= sizeof(int)) &&
          (!md->check_correct.values.rangeminmax  || md->range_hi >= 2*sizeof(uint64_t)) &&
          (!md->check_correct.values.sendminalign || md->send_min_align >= sizeof(char)) &&
          (!md->check_correct.values.recvminalign || md->recv_min_align >= sizeof(char))) {
        break; /* Otherwise fall through */
      }
    }
    dfltval = "I1:ShortAllreduce:"; /* excellent second choice on BG/Q */
    alg = gasnetc_find_alg(dfltval, metadata, fullcount);
    if (alg < fullcount) {
      /* make sure PAMI-allreduce barrier and exitcode reduction will "fit" */
      pami_metadata_t *md = &metadata[alg];
      if ((!md->check_correct.values.rangeminmax  || md->range_lo <= sizeof(int)) &&
          (!md->check_correct.values.rangeminmax  || md->range_hi >= 2*sizeof(uint64_t)) &&
          (!md->check_correct.values.sendminalign || md->send_min_align >= sizeof(char)) &&
          (!md->check_correct.values.recvminalign || md->recv_min_align >= sizeof(char))) {
        break; /* Otherwise fall through */
      }
    }
  #endif
    dfltval = "I0:Binomial:"; /* uniformly "good" on BG/Q and PERCS */
    break;

  /* Used for gasnetc_fast_barrier() and GASNET_BARRIERFLAG_UNNAMED */
  case PAMI_XFER_BARRIER:
    envvar = "GASNET_PAMI_BARRIER_ALG";
  #if GASNETI_ARCH_BGQ
    /* Note: this could be any of
     *     "I0:MultiSync2Device:SHMEM:GI"
     *     "I0:MultiSync:SHMEM:-",
     *     "I0:MultiSync:-:GI",
     * depending on job layout, and may not be available on team != ALL.
     */
    dfltval = "I0:MultiSync";
    alg = gasnetc_find_alg(dfltval, metadata, counts[0]);
    if (alg < counts[0]) break; /* Otherwise fall through */
  #endif
    dfltval = NULL; /* TODO: tune a better default than alg[0]? */
    break;

  /* Used for blocking gasnet broadcast: */
  case PAMI_XFER_BROADCAST:
    envvar = "GASNET_PAMI_BROADCAST_ALG";
  #if GASNETI_ARCH_BGQ
    dfltval = "I0:2-nary:"; /* uniformly "near-best" on BG/Q */
  #else
   #if 0 /* Seen to deadlock when using multiple procs/node */
    dfltval = "I0:4-nary:"; /* uniformly "near-best" on PERSC */
   #else
    dfltval = NULL; /* TODO: tune for better default or wait for bug fix */
   #endif
  #endif
    break;

  /* Used for blocking gasnet gather: */
  case PAMI_XFER_GATHER:
    envvar = "GASNET_PAMI_GATHER_ALG";
    dfltval = NULL; /* TODO: tune for better default */
    break;

  /* Used for blocking gasnet gather w/ multiple images: */
  case PAMI_XFER_GATHERV_INT:
    envvar = "GASNET_PAMI_GATHERV_INT_ALG";
    dfltval = NULL; /* TODO: tune for better default */
    break;

  /* Used for blocking gasnet scatter: */
  case PAMI_XFER_SCATTER:
    envvar = "GASNET_PAMI_SCATTER_ALG";
    dfltval = "I0:Binomial:"; /* uniformly "good" on BG/Q and PERSC */
    break;

  /* Used for blocking gasnet scatter w/ multiple images: */
  case PAMI_XFER_SCATTERV_INT:
    envvar = "GASNET_PAMI_SCATTERV_INT_ALG";
    dfltval = NULL; /* TODO: tune for better default */
    break;

  default:
    gasneti_fatalerror("Unknown 'op' value %d in %s", (int)op, __FUNCTION__);
    envvar = dfltval = NULL; /* for warning suppression only */
  }
  /* Override the defaults above for the single-task case: */
  if (gasneti_nodes == 1) {
    const char *onetask = "I0:OneTask";
    if (gasnetc_find_alg(onetask, metadata, counts[0]) < counts[0]) {
      dfltval = onetask;
    }
  }
  /* Now the user's environment value if any: */
  envval = gasneti_getenv_withdefault(envvar, dfltval);
  alg = 0; /* failsafe */
  if (NULL != envval) {
    while (envval[0] && isspace(envval[0])) ++envval; /* leading whitespace */
    if (!envval[0]) {
      /* empty - treat as zero */
    } else if (0 == strcmp("LIST", envval)) {
      if (!gasneti_mynode && !print_once[(int)op]) {
        int i;
        fprintf(stderr, "Listing available values for environment variable %s:\n", envvar);
        for (i=0; i<fullcount; ++i) {
          fprintf(stderr, " %c %3d %s\n", ((i<counts[0])?' ':'*'), i, metadata[i].name);
        }
        if (counts[1]) {
          fprintf(stderr,
                  "Note: Lines marked with '*' may not be valid for all inputs and/or job layouts.\n"
                  "      The user is responsible for ensuring only valid algorithms are requested.\n"
                 );
        }
        print_once[(int)op] = 1;
      }
    } else if (isdigit(envval[0])) {
      /* integer is used just as given */
      alg = atoi(envval);
      if (alg < 0 || alg >= fullcount) {
        if (!gasneti_mynode && !print_once[(int)op]) {
          fprintf(stderr, "WARNING: Ignoring value '%d' for environment variable %s,\n"
                          "         because it is outside the range of available algorithms.\n"
                          "         Set this variable to LIST for a list of all algorithms.\n",
                           alg, envvar);
          print_once[(int)op] = 1;
        }
        alg = 0;
      }
    } else {
      /* string is used for PREFIX match */
      alg = gasnetc_find_alg(envval, metadata, fullcount);
      if (alg == fullcount) {
        if (!gasneti_mynode && !print_once[(int)op] && (envval != dfltval)) {
          fprintf(stderr, "WARNING: Ignoring value '%s' for environment variable %s,\n"
                          "         because it does not match any available algorithm.\n"
                          "         Set this variable to LIST for a list of all algorithms.\n",
                           envval, envvar);
          print_once[(int)op] = 1;
        }
        alg = 0;
      }
    }
  }

  *alg_p = algorithms[alg];
}
Ejemplo n.º 2
0
static int gasnetc_init(int *argc, char ***argv) {
  int retval = GASNET_OK;

  /*  check system sanity */
  gasnetc_check_config();

  /* --------- begin Master code ------------ */
  if (!AMUDP_SPMDIsWorker(argv?*argv:NULL)) {
    /* assume we're an implicit master 
       (we don't currently support explicit workers spawned 
        without using the AMUDP SPMD API)   
     */
    int num_nodes;
    int i;
    char spawnfn;
    amudp_spawnfn_t fp = (amudp_spawnfn_t)NULL;

    if (!argv) {
      gasneti_fatalerror("implicit-master without argv not supported - use amudprun");
    }

    /* pretend we're node 0, for purposes of verbose env reporting */
    gasneti_init_done = 1;
    gasneti_mynode = 0;

    #if defined(GASNET_CSPAWN_CMD)
    { /* set configure default cspawn cmd */
      const char *cmd = gasneti_getenv_withdefault("GASNET_CSPAWN_CMD",GASNET_CSPAWN_CMD);
      gasneti_setenv("GASNET_CSPAWN_CMD",cmd);
    }
    #endif

    /* parse node count from command line */
    if (*argc < 2) {
      fprintf(stderr, "GASNet: Missing parallel node count\n");
      fprintf(stderr, "GASNet: Specify node count as first argument, or use upcrun/tcrun spawner script to start job\n");
      fprintf(stderr, "GASNet: Usage '%s <num_nodes> {program arguments}'\n", (*argv)[0]);
      exit(-1);
    }
    /*
     * argv[1] is number of nodes; argv[0] is program name; argv is
     * list of arguments including program name and number of nodes.
     * We need to remove argv[1] when the argument array is passed
     * to the tic_main().
     */
    num_nodes = atoi((*argv)[1]);
    if (num_nodes < 1) {
      fprintf (stderr, "GASNet: Invalid number of nodes: %s\n", (*argv)[1]);
      fprintf (stderr, "GASNet: Usage '%s <num_nodes> {program arguments}'\n", (*argv)[0]);
      exit (1);
    }

    /* remove the num_nodes argument */
    for (i = 1; i < (*argc)-1; i++) {
      (*argv)[i] = (*argv)[i+1];
    }
    (*argv)[(*argc)-1] = NULL;
    (*argc)--;

    /* get spawnfn */
    spawnfn = *gasneti_getenv_withdefault("GASNET_SPAWNFN", _STRINGIFY(GASNETC_DEFAULT_SPAWNFN));

    { /* ensure we pass the effective spawnfn to worker env */
      char spawnstr[2];
      spawnstr[0] = toupper(spawnfn);
      spawnstr[1] = '\0';
      gasneti_setenv("GASNET_SPAWNFN",spawnstr);
    }

    /* ensure reliable localhost operation by forcing use of 127.0.0.1
     * setting GASNET_MASTERIP to the empty string will prevent this */
    if (('L' == toupper(spawnfn)) && !gasneti_getenv("GASNET_MASTERIP")) {
      gasneti_setenv("GASNET_MASTERIP","127.0.0.1");
    }

    for (i=0; AMUDP_Spawnfn_Desc[i].abbrev; i++) {
      if (toupper(spawnfn) == toupper(AMUDP_Spawnfn_Desc[i].abbrev)) {
        fp = AMUDP_Spawnfn_Desc[i].fnptr;
        break;
      }
    }

    if (!fp) {
      fprintf (stderr, "GASNet: Invalid spawn function specified in GASNET_SPAWNFN\n");
      fprintf (stderr, "GASNet: The following mechanisms are available:\n");
      for (i=0; AMUDP_Spawnfn_Desc[i].abbrev; i++) {
        fprintf(stderr, "    '%c'  %s\n",  
              toupper(AMUDP_Spawnfn_Desc[i].abbrev), AMUDP_Spawnfn_Desc[i].desc);
      }
      exit(1);
    }

    #if GASNET_DEBUG_VERBOSE
      /* note - can't call trace macros during gasnet_init because trace system not yet initialized */
      fprintf(stderr,"gasnetc_init(): about to spawn...\n"); fflush(stderr);
    #endif

    retval = AMUDP_SPMDStartup(argc, argv, 
      num_nodes, 0, fp,
      NULL, &gasnetc_bundle, &gasnetc_endpoint);
    /* master startup should never return */
    gasneti_fatalerror("master AMUDP_SPMDStartup() failed");
  }

  /* --------- begin Worker code ------------ */
  AMLOCK();
    if (gasneti_init_done) 
      INITERR(NOT_INIT, "GASNet already initialized");

    gasneti_freezeForDebugger();

    AMUDP_VerboseErrors = gasneti_VerboseErrors;
    AMUDP_SPMDkillmyprocess = gasneti_killmyprocess;

    /*  perform job spawn */
    retval = AMUDP_SPMDStartup(argc, argv, 
      0, 0, NULL, /* dummies */
      &gasnetc_networkpid, &gasnetc_bundle, &gasnetc_endpoint);
    if (retval != AM_OK) INITERR(RESOURCE, "slave AMUDP_SPMDStartup() failed");
    gasneti_init_done = 1; /* enable early to allow tracing */

    gasneti_conduit_getenv = (/* cast drops const */ gasneti_getenv_fn_t*)&AMUDP_SPMDgetenvMaster;
    gasneti_mynode = AMUDP_SPMDMyProc();
    gasneti_nodes = AMUDP_SPMDNumProcs();

    /* enable tracing */
    gasneti_trace_init(argc, argv);
    GASNETI_AM_SAFE(AMUDP_SPMDSetExitCallback(gasnetc_traceoutput));

    /* for local spawn, assume we want to wait-block */
    if (gasneti_getenv("GASNET_SPAWNFN") && *gasneti_getenv("GASNET_SPAWNFN") == 'L') { 
      GASNETI_TRACE_PRINTF(C,("setting gasnet_set_waitmode(GASNET_WAIT_BLOCK) for localhost spawn"));
      gasnet_set_waitmode(GASNET_WAIT_BLOCK);
    }

    #if GASNET_DEBUG_VERBOSE
      fprintf(stderr,"gasnetc_init(): spawn successful - node %i/%i starting...\n", 
        gasneti_mynode, gasneti_nodes); fflush(stderr);
    #endif

    gasneti_nodemapInit(&gasnetc_bootstrapExchange, NULL, 0, 0);

    #if GASNET_PSHM
      gasneti_pshm_init(&gasnetc_bootstrapSNodeBroadcast, 0);
    #endif

    #if GASNET_SEGMENT_FAST || GASNET_SEGMENT_LARGE
    { uintptr_t limit;
      #if HAVE_MMAP
        limit = gasneti_mmapLimit((uintptr_t)-1, (uint64_t)-1,
                                  &gasnetc_bootstrapExchange,
                                  &gasnetc_bootstrapBarrier);
      #else
        limit = (intptr_t)-1;
      #endif
      gasneti_segmentInit(limit, &gasnetc_bootstrapExchange);
    }
    #elif GASNET_SEGMENT_EVERYTHING
      /* segment is everything - nothing to do */
    #else
      #error Bad segment config
    #endif

    #if GASNET_BLCR
      gasneti_checkpoint_guid = gasnetc_networkpid;
      gasneti_checkpoint_init(NULL);
    #endif

  AMUNLOCK();

  gasneti_auxseg_init(); /* adjust max seg values based on auxseg */

  gasneti_assert(retval == GASNET_OK);
  return retval;

done: /*  error return while locked */
  AMUNLOCK();
  GASNETI_RETURN(retval);
}
Ejemplo n.º 3
0
static int gasnetc_init(int *argc, char ***argv, gex_Flags_t flags) {
  int retval = GASNET_OK;

  /*  check system sanity */
  gasnetc_check_config();

  /* --------- begin Master code ------------ */
  if (!AMUDP_SPMDIsWorker(argv?*argv:NULL)) {
    /* assume we're an implicit master 
       (we don't currently support explicit workers spawned 
        without using the AMUDP SPMD API)   
     */
    int num_nodes;
    int i;
    char spawnfn;
    amudp_spawnfn_t fp = (amudp_spawnfn_t)NULL;

    if (!argv) {
      gasneti_fatalerror("implicit-master without argv not supported - use amudprun");
    }

    /* pretend we're node 0, for purposes of verbose env reporting */
    gasneti_init_done = 1;
    gasneti_mynode = 0;

    #if defined(GASNET_CSPAWN_CMD)
    { /* set configure default cspawn cmd */
      const char *cmd = gasneti_getenv_withdefault("GASNET_CSPAWN_CMD",GASNET_CSPAWN_CMD);
      gasneti_setenv("GASNET_CSPAWN_CMD",cmd);
    }
    #endif

    /* parse node count from command line */
    if (*argc < 2) {
      fprintf(stderr, "GASNet: Missing parallel node count\n");
      fprintf(stderr, "GASNet: Specify node count as first argument, or use upcrun/tcrun spawner script to start job\n");
      fprintf(stderr, "GASNet: Usage '%s <num_nodes> {program arguments}'\n", (*argv)[0]);
      exit(-1);
    }
    /*
     * argv[1] is number of nodes; argv[0] is program name; argv is
     * list of arguments including program name and number of nodes.
     * We need to remove argv[1] when the argument array is passed
     * to the tic_main().
     */
    num_nodes = atoi((*argv)[1]);
    if (num_nodes < 1) {
      fprintf (stderr, "GASNet: Invalid number of nodes: %s\n", (*argv)[1]);
      fprintf (stderr, "GASNet: Usage '%s <num_nodes> {program arguments}'\n", (*argv)[0]);
      exit (1);
    }

    /* remove the num_nodes argument */
    for (i = 1; i < (*argc)-1; i++) {
      (*argv)[i] = (*argv)[i+1];
    }
    (*argv)[(*argc)-1] = NULL;
    (*argc)--;

    /* get spawnfn */
    spawnfn = *gasneti_getenv_withdefault("GASNET_SPAWNFN", _STRINGIFY(GASNETC_DEFAULT_SPAWNFN));

    { /* ensure we pass the effective spawnfn to worker env */
      char spawnstr[2];
      spawnstr[0] = toupper(spawnfn);
      spawnstr[1] = '\0';
      gasneti_setenv("GASNET_SPAWNFN",spawnstr);
    }

    /* ensure reliable localhost operation by forcing use of 127.0.0.1
     * setting GASNET_MASTERIP to the empty string will prevent this */
    if (('L' == toupper(spawnfn)) && !gasneti_getenv("GASNET_MASTERIP")) {
      gasneti_setenv("GASNET_MASTERIP","127.0.0.1");
    }

    for (i=0; AMUDP_Spawnfn_Desc[i].abbrev; i++) {
      if (toupper(spawnfn) == toupper(AMUDP_Spawnfn_Desc[i].abbrev)) {
        fp = AMUDP_Spawnfn_Desc[i].fnptr;
        break;
      }
    }

    if (!fp) {
      fprintf (stderr, "GASNet: Invalid spawn function specified in GASNET_SPAWNFN\n");
      fprintf (stderr, "GASNet: The following mechanisms are available:\n");
      for (i=0; AMUDP_Spawnfn_Desc[i].abbrev; i++) {
        fprintf(stderr, "    '%c'  %s\n",  
              toupper(AMUDP_Spawnfn_Desc[i].abbrev), AMUDP_Spawnfn_Desc[i].desc);
      }
      exit(1);
    }

    #if GASNET_DEBUG_VERBOSE
      /* note - can't call trace macros during gasnet_init because trace system not yet initialized */
      fprintf(stderr,"gasnetc_init(): about to spawn...\n"); fflush(stderr);
    #endif

    retval = AMUDP_SPMDStartup(argc, argv, 
      num_nodes, 0, fp,
      NULL, &gasnetc_bundle, &gasnetc_endpoint);
    /* master startup should never return */
    gasneti_fatalerror("master AMUDP_SPMDStartup() failed");
  }

  /* --------- begin Worker code ------------ */
  AMLOCK();
    if (gasneti_init_done) 
      INITERR(NOT_INIT, "GASNet already initialized");

    gasneti_freezeForDebugger();

    AMX_VerboseErrors = gasneti_VerboseErrors;
    AMUDP_SPMDkillmyprocess = gasneti_killmyprocess;

#if GASNETI_CALIBRATE_TSC
    // Early x86*/Linux timer initialization before AMUDP_SPMDStartup()
    //
    // udp-conduit does not support user-provided values for GASNET_TSC_RATE*
    // (which fine-tune timer calibration on x86/Linux).  This is partially due
    // to a dependency cycle at startup with envvar propagation, but more
    // importantly because the retransmission algorithm (and hence all conduit
    // comms) rely on gasnet timers to be accurate (at least approximately), so
    // we don't allow the user to weaken or disable their calibration.
    gasneti_unsetenv("GASNET_TSC_RATE");
    gasneti_unsetenv("GASNET_TSC_RATE_TOLERANCE");
    gasneti_unsetenv("GASNET_TSC_RATE_HARD_TOLERANCE");
    GASNETI_TICKS_INIT();
#endif

    /*  perform job spawn */
    retval = AMUDP_SPMDStartup(argc, argv, 
      0, 0, NULL, /* dummies */
      &gasnetc_networkpid, &gasnetc_bundle, &gasnetc_endpoint);
    if (retval != AM_OK) INITERR(RESOURCE, "slave AMUDP_SPMDStartup() failed");
    gasneti_init_done = 1; /* enable early to allow tracing */

    gasneti_getenv_hook = (/* cast drops const */ gasneti_getenv_fn_t*)&AMUDP_SPMDgetenvMaster;
    gasneti_mynode = AMUDP_SPMDMyProc();
    gasneti_nodes = AMUDP_SPMDNumProcs();

#if !GASNETI_CALIBRATE_TSC
    /* Must init timers after global env, and preferably before tracing */
    GASNETI_TICKS_INIT();
#endif

    /* enable tracing */
    gasneti_trace_init(argc, argv);
    GASNETI_AM_SAFE(AMUDP_SPMDSetExitCallback(gasnetc_traceoutput));

    /* for local spawn, assume we want to wait-block */
    if (gasneti_getenv("GASNET_SPAWNFN") && *gasneti_getenv("GASNET_SPAWNFN") == 'L') { 
      GASNETI_TRACE_PRINTF(C,("setting gasnet_set_waitmode(GASNET_WAIT_BLOCK) for localhost spawn"));
      gasnet_set_waitmode(GASNET_WAIT_BLOCK);
    }

    #if GASNET_DEBUG_VERBOSE
      fprintf(stderr,"gasnetc_init(): spawn successful - node %i/%i starting...\n", 
        gasneti_mynode, gasneti_nodes); fflush(stderr);
    #endif

    gasneti_nodemapInit(&gasnetc_bootstrapExchange, NULL, 0, 0);

    #if GASNET_PSHM
      gasneti_pshm_init(&gasnetc_bootstrapSNodeBroadcast, 0);
    #endif

    uintptr_t mmap_limit;
    #if HAVE_MMAP
      mmap_limit = gasneti_mmapLimit((uintptr_t)-1, (uint64_t)-1,
                                  &gasnetc_bootstrapExchange,
                                  &gasnetc_bootstrapBarrier);
    #else
      // TODO-EX: we can at least look at rlimits but such logic belongs in conduit-indep code
      mmap_limit = (intptr_t)-1;
    #endif

    /* allocate and attach an aux segment */

    gasneti_auxsegAttach(mmap_limit, &gasnetc_bootstrapExchange);

    /* determine Max{Local,GLobal}SegmentSize */
    gasneti_segmentInit(mmap_limit, &gasnetc_bootstrapExchange, flags);

    #if GASNET_BLCR
      gasneti_checkpoint_guid = gasnetc_networkpid;
      gasneti_checkpoint_init(NULL);
    #endif

  AMUNLOCK();

  gasneti_assert(retval == GASNET_OK);
  return retval;

done: /*  error return while locked */
  AMUNLOCK();
  GASNETI_RETURN(retval);
}