/** * I shouldn't really initialize more than once */ static inline int check_pe_status (void) { int yn = 1; const pe_status_t s = GET_STATE (pe_status); switch (s) { case PE_UNINITIALIZED: /* this is what it should be */ yn = 1; break; case PE_UNKNOWN: case PE_RUNNING: case PE_SHUTDOWN: case PE_FAILED: shmemi_trace (SHMEM_LOG_INFO, "OpenSHMEM has already been initialized (%s)", shmemi_state_as_string (s)); yn = 0; break; default: /* shouldn't be here */ yn = 0; break; } return yn; }
/** * initialize the ping sub-system. Respect any environment setting * asking for different ping timeout. * */ void shmemi_ping_init (void) { #if 0 double timeout = DEFAULT_PE_ACCESSIBLE_TIMEOUT; char *pt = shmemi_comms_getenv (ping_timeout_envvar); if (pt != (char *) NULL) { timeout = atof (pt); } /* sanity check it */ if (timeout < 0.0) { double ot = timeout; timeout = DEFAULT_PE_ACCESSIBLE_TIMEOUT; shmemi_trace (SHMEM_LOG_INIT, "PE accessibility timeout %f negative, reset to default %f sec", ot, timeout); } shmemi_set_ping_timeout (timeout); assign_timer (0, 0, &zero); #endif }
/* * Tree based broadcast generates a binary tree with the PEs in the * active with PE_root as the root. The puts happen in a top down * approach. * */ static inline void set_2tree (int PE_start, int PE_stride, int PE_size, int *parent, int *child_l, int *child_r, int my_pe) { int max_pe = PE_start + PE_stride * (PE_size - 1); *child_l = 2 * (my_pe - PE_start) + PE_stride + PE_start; *child_r = *child_l + PE_stride; /* set parent */ if (my_pe == PE_start) { *parent = -1; } else { *parent = (my_pe - PE_start - PE_stride) / 2; *parent -= *parent % PE_stride; *parent += PE_start; } if (*child_l > max_pe) { *child_l = *child_r = -1; } else if (*child_r > max_pe) { *child_r = -1; } shmemi_trace (SHMEM_LOG_BROADCAST, "set2tree: parent = %d, L_child = %d, R_child = %d", *parent, *child_l, *child_r); }
void shmemi_barrier_linear (int PE_start, int logPE_stride, int PE_size, long *pSync) { const int me = shmem_my_pe (); const int step = 1 << logPE_stride; const long nreplies = SHMEM_SYNC_VALUE + PE_size - 1; int i, round; int thatpe; for (round = 0; round < 2; round += 1) { for (thatpe = PE_start, i = 0; i < PE_size; thatpe += step, i += 1) { if (thatpe != me) { shmem_long_inc (&pSync[round], thatpe); shmemi_trace (SHMEM_LOG_BARRIER, "round = %d, sent increment to PE %d", round, thatpe); } } shmem_long_wait_until (&pSync[round], SHMEM_CMP_EQ, nreplies); pSync[round] = SHMEM_SYNC_VALUE; } }
static void print_global_var_table (shmem_trace_t msgtype) { globalvar_t *g; globalvar_t *tmp; if (!shmemi_trace_is_enabled (msgtype)) { return; } shmemi_trace (msgtype, "-- start hash table --"); HASH_SORT (gvp, addr_sort); HASH_ITER (hh, gvp, g, tmp) { shmemi_trace (msgtype, "address %p: name \"%s\", size %ld", g->addr, g->name, g->size); }
void debug_alloc_dump (void) { alloc_table_t *tmp; alloc_table_t *s; HASH_ITER (hh, atp, s, tmp) { shmemi_trace (SHMEM_LOG_MEMORY, "addr = %p, size = %ld", s->addr, s->size); }
/** * inspect our own executable: find the real program name, and open a * file descriptor */ void shmemi_executable_init (void) { ssize_t s; int fd; /* see if the shortcut works */ s = readlink (self, GET_STATE (exe_name), MAXPATHLEN - 1); /* if not, try finding our PID */ if (EXPR_UNLIKELY (s < 0)) { char buf[MAXPATHLEN]; snprintf (buf, MAXPATHLEN, self_fmt, getpid ()); s = readlink (buf, GET_STATE (exe_name), MAXPATHLEN - 1); } /* dunno who I am, complain */ if (EXPR_UNLIKELY (s < 0)) { shmemi_trace (SHMEM_LOG_FATAL, "can't find my own executable name (%s)", strerror (errno)); goto bail; /* NOT REACHED */ } /* bleagh, readlink doesn't null-terminate */ GET_STATE (exe_name)[s] = '\0'; /* get a file descriptor */ fd = open (GET_STATE (exe_name), O_RDONLY, 0); if (EXPR_UNLIKELY (fd < 0)) { shmemi_trace (SHMEM_LOG_FATAL, "can't open \"%s\" (%s)", GET_STATE (exe_name), strerror (errno)); return; /* NOT REACHED */ } SET_STATE (exe_fd, fd); bail: return; }
/** * set the time out. Can also be used to tune library behavior * */ void shmemi_set_ping_timeout (double secs) { #if 0 parse_alarm_time (secs, &GET_STATE (ping_timeout)); shmemi_trace (SHMEM_LOG_INIT, "PE accessibility timeout set to %f sec", secs); #endif }
void shmemi_symmetric_test_with_abort (void *remote_addr, void *local_addr, const char *name, const char *routine) { if (EXPR_UNLIKELY (remote_addr == NULL)) { shmemi_trace (SHMEM_LOG_FATAL, "shmem_%s_%s: address %p is not symmetric", name, routine, local_addr); /* NOT REACHED */ } }
static inline void report_up (void) { int maj, min; const int n = GET_STATE (numpes); const size_t h = GET_STATE (heapsize); if (shmemi_version (&maj, &min) == 0) { shmemi_trace (SHMEM_LOG_INIT, "version %d.%d running on %d PE%s, using %zd bytes of symmetric heap", maj, min, n, (n == 1) ? "" : "s", h); } }
/** * clear the alarm after doing a ping * */ void shmemi_ping_clear_alarm (void) { #if 0 int s = setitimer (ITIMER_REAL, &zero, NULL); if (s != 0) { shmemi_trace (SHMEM_LOG_FATAL, "internal error: couldn't clear accessibility timer (%s)", strerror (errno)); return; /* NOT REACHED */ } #endif }
/** * set up the alarm before doing a ping * */ void shmemi_ping_set_alarm (void) { #if 0 int s = setitimer (ITIMER_REAL, &GET_STATE (ping_timeout), NULL); if (s != 0) { shmemi_trace (SHMEM_LOG_FATAL, "internal error: couldn't set accessibility timer (%s)", strerror (errno)); return; /* NOT REACHED */ } #endif }
void debug_alloc_del (void *a) { alloc_table_t *at = debug_alloc_find (a); if (at == NULL) { shmemi_trace (SHMEM_LOG_FATAL, "internal error: no hash table entry for address %p", a); return; /* NOT REACHED */ } HASH_DEL (atp, at); free (at); }
static inline alloc_table_t * debug_alloc_new (void *a, size_t s) { alloc_table_t *at = (alloc_table_t *) malloc (sizeof (*at)); if (at == NULL) { shmemi_trace (SHMEM_LOG_FATAL, "internal error: out of memory" " allocating address/size record"); return NULL; /* NOT REACHED */ } at->addr = a; at->size = s; return at; }
void * shmem_ptr (const void *target, int pe) { INIT_CHECK (); PE_RANGE_CHECK (pe, 2); #ifdef SHMEM_PUTGET_SHARED_MEMORY shmemi_trace (SHMEM_LOG_NOTICE, "shmem_ptr() not implemented yet"); return (void *) NULL; #else /* ! SHMEM_PUTGET_SHARED_MEMORY */ return (void *) NULL; #endif /* SHMEM_PUTGET_SHARED_MEMORY */ }
int debug_alloc_check (void *a) { alloc_table_t *tmp; alloc_table_t *s; HASH_ITER (hh, atp, s, tmp) { const size_t off = a - s->addr; /* if ( (s->size > off) && (off >= 0) ) */ if (s->size > off) { return 1; /* NOT REACHED */ } } shmemi_trace (SHMEM_LOG_MEMORY, "address %p is not in a known symmetric allocation", a); return 0; }
void shmem_pcontrol (int level) { char *msg = NULL; switch (level) { case 0: msg = "disabled"; break; case 1: msg = "enabled (default detail)"; break; default: msg = "tool-specific"; break; } shmemi_trace (SHMEM_LOG_INFO, "shmem_pcontrol(%d) is %s", level, msg); return; }
static inline void shmem_init_private (int npes) { if (!check_pe_status ()) { return; } shmemi_comms_init (); /* just note start_pes() not passed 0, it's not a big deal */ if (npes != 0) { shmemi_trace (SHMEM_LOG_INFO, "start_pes() was passed %d, should be 0", npes); } report_up (); /* * and we're up and running */ }
/** * return number of (fractional) seconds * since program started */ static inline double read_clock (void) { struct timeval tv; double t; int s; s = gettimeofday (&tv, (struct timezone *) NULL); if (EXPR_UNLIKELY (s != 0)) { shmemi_trace (SHMEM_LOG_FATAL, "internal error: can't read system clock (%s)", strerror (errno) ); /* NOT REACHED */ } t = (double) tv.tv_sec; t += (double) tv.tv_usec / 1000000.0; return t; }
void shmemi_collect_dispatch_init (void) { char *name = shmemi_comms_getenv ("SHMEM_COLLECT_ALGORITHM"); if (EXPR_LIKELY (name == (char *) NULL)) { name = default_implementation; } if (strcmp (name, "linear") == 0) { func32 = shmemi_collect32_linear; func64 = shmemi_collect64_linear; } else { ; /* error */ } /* * report which implementation we set up */ shmemi_trace (SHMEM_LOG_BROADCAST, "using collect \"%s\"", name); }
void shmemi_barrier_tree (int PE_start, int logPE_stride, int PE_size, long *pSync) { int child_l, child_r, parent; const int step = 1 << logPE_stride; int my_pe = GET_STATE (mype); int no_children; long is_ready, lchild_ready, rchild_ready; is_ready = 1; lchild_ready = -1; rchild_ready = -1; shmem_long_wait_until (&pSync[0], SHMEM_CMP_EQ, SHMEM_SYNC_VALUE); shmem_long_wait_until (&pSync[1], SHMEM_CMP_EQ, SHMEM_SYNC_VALUE); /* printf("Tree barrier\n"); */ set_2tree (PE_start, step, PE_size, &parent, &child_l, &child_r, my_pe); no_children = 0; shmemi_trace (SHMEM_LOG_BARRIER, "before barrier, R_child = %d L_child = %d", child_r, child_l); /* The actual barrier */ if (PE_size > 1) { pSync[0] = 0; pSync[1] = 0; if (my_pe == PE_start) { pSync[0] = SHMEM_SYNC_VALUE; if (child_l != -1) { shmem_long_get (&lchild_ready, (const long *) &pSync[0], 1, child_l); while (lchild_ready != 0) shmem_long_get (&lchild_ready, &pSync[0], 1, child_l); shmem_long_put (&pSync[0], &is_ready, 1, child_l); no_children = 1; } if (child_r != -1) { shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); while (rchild_ready != 0) shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); shmem_long_put (&pSync[0], &is_ready, 1, child_r); no_children = 2; } shmem_long_wait_until (&pSync[1], SHMEM_CMP_EQ, (long) no_children); pSync[1] = SHMEM_SYNC_VALUE; } else { shmem_long_wait_until (&pSync[0], SHMEM_CMP_EQ, is_ready); shmemi_trace (SHMEM_LOG_BARRIER, "inside else"); if (child_l != -1) { shmem_long_get (&lchild_ready, &pSync[0], 1, child_l); while (lchild_ready != 0) shmem_long_get (&lchild_ready, &pSync[0], 1, child_l); shmem_long_put (&pSync[0], &is_ready, 1, child_l); no_children = 1; } if (child_r != -1) { shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); while (rchild_ready != 0) shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); shmem_long_put (&pSync[0], &is_ready, 1, child_r); no_children = 2; } pSync[0] = SHMEM_SYNC_VALUE; if (no_children == 0) { pSync[1] = SHMEM_SYNC_VALUE; shmem_long_inc (&pSync[1], parent); } else { shmem_long_wait_until (&pSync[1], SHMEM_CMP_EQ, (long) no_children); pSync[1] = SHMEM_SYNC_VALUE; shmem_long_inc (&pSync[1], parent); } } shmemi_trace (SHMEM_LOG_BARRIER, "at the end of barrier"); } }
/* * scan the ELF image to build table of global symbold and the image * regions where they can be found (BSS and DATA) */ static inline int table_init_helper (void) { Elf *e = NULL; GElf_Ehdr ehdr; char *shstr_name = NULL; size_t shstrndx; Elf_Scn *scn = NULL; GElf_Shdr shdr; int ret = -1; #if 0 int (*getsi) (); /* look up name of elf_get... routine */ #endif /* unrecognized format */ if (elf_version (EV_CURRENT) == EV_NONE) { goto bail; } /* get the ELF object from already opened state */ e = elf_begin (GET_STATE (exe_fd), ELF_C_READ, NULL); if (e == NULL) { goto bail; } /* do some sanity checks */ if (elf_kind (e) != ELF_K_ELF) { goto bail; } if (gelf_getehdr (e, &ehdr) == NULL) { goto bail; } if (gelf_getclass (e) == ELFCLASSNONE) { goto bail; } /* * There are various elf_get* routines with different return values * in differnt libraries/versions - name of routine does not tell us * all we ned to know. So let it go here, and we'll mop up any * problems later on. */ /* * This routine is either "elf_getshdrstrndx" in newer ELF * libraries, or "elf_getshstrndx" in older ones. Hard-code older * one for now since it is in the newer libraries, although marked as * deprecated. This will be detected by autoconf later * * DEPRECATED */ (void) elf_getshstrndx (e, &shstrndx); /* walk sections, look for RO/BSS/DATA and symbol table */ scn = NULL; while ((scn = elf_nextscn (e, scn)) != NULL) { if (gelf_getshdr (scn, &shdr) != &shdr) { goto bail; } shstr_name = elf_strptr (e, shstrndx, shdr.sh_name); if (shstr_name == NULL) { goto bail; } /* found the read-only data */ if (shdr.sh_type == SHT_PROGBITS && strcmp (shstr_name, ".rodata") == 0) { elfro.start = shdr.sh_addr; elfro.end = elfro.start + shdr.sh_size; shmemi_trace (SHMEM_LOG_SYMBOLS, "ELF section .rodata for global variables = 0x%lX -> 0x%lX", elfro.start, elfro.end); continue; /* move to next scan */ } /* found the uninitialized globals */ if (shdr.sh_type == SHT_NOBITS && strcmp (shstr_name, ".bss") == 0) { elfbss.start = shdr.sh_addr; elfbss.end = elfbss.start + shdr.sh_size; shmemi_trace (SHMEM_LOG_SYMBOLS, "ELF section .bss for global variables = 0x%lX -> 0x%lX", elfbss.start, elfbss.end); continue; /* move to next scan */ } /* found the initialized globals */ if (shdr.sh_type == SHT_PROGBITS && strcmp (shstr_name, ".data") == 0) { elfdata.start = shdr.sh_addr; elfdata.end = elfdata.start + shdr.sh_size; shmemi_trace (SHMEM_LOG_SYMBOLS, "ELF section .data for global variables = 0x%lX -> 0x%lX", elfdata.start, elfdata.end); continue; /* move to next scan */ } /* keep looking until we find the symbol table */ if (shdr.sh_type == SHT_SYMTAB) { Elf_Data *data = NULL; while ((data = elf_getdata (scn, data)) != NULL) { GElf_Sym *es; GElf_Sym *last_es; es = (GElf_Sym *) data->d_buf; if (es == NULL) { continue; } /* find out how many entries to look for */ last_es = (GElf_Sym *) ((char *) data->d_buf + data->d_size); for (; es < last_es; es += 1) { char *name; /* * need visible global or local (Fortran save) object with * some kind of content */ if (es->st_value == 0 || es->st_size == 0) { continue; } /* * this macro handles a symbol that is present * in one libelf implementation but isn't in another * (elfutils vs. libelf) */ #ifndef GELF_ST_VISIBILITY #define GELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o) #endif if (GELF_ST_TYPE (es->st_info) != STT_OBJECT && GELF_ST_VISIBILITY (es->st_info) != STV_DEFAULT) { continue; } name = elf_strptr (e, shdr.sh_link, (size_t) es->st_name); if (name == NULL || *name == '\0') { continue; } /* put the symbol and info into the symbol hash table */ { globalvar_t *gv = (globalvar_t *) malloc (sizeof (*gv)); if (gv == NULL) { goto bail; } gv->name = strdup (name); if (gv->name == NULL) { free (gv); goto bail; } gv->addr = (void *) es->st_value; gv->size = es->st_size; HASH_ADD_PTR (gvp, addr, gv); } } } /* * pulled out all the global symbols => success, * don't need to scan further */ ret = 0; break; } } bail: if (elf_end (e) != 0) { ret = -1; } return ret; }
void shmemi_broadcast32_tree (void *target, const void *source, size_t nlong, int PE_root, int PE_start, int logPE_stride, int PE_size, long *pSync) { int child_l, child_r, parent; const int step = 1 << logPE_stride; int my_pe = GET_STATE (mype); int *target_ptr, *source_ptr; int no_children; long is_ready, lchild_ready, rchild_ready; is_ready = 1; lchild_ready = -1; rchild_ready = -1; shmem_long_wait_until (&pSync[0], SHMEM_CMP_EQ, SHMEM_SYNC_VALUE); shmem_long_wait_until (&pSync[1], SHMEM_CMP_EQ, SHMEM_SYNC_VALUE); pSync[0] = 0; pSync[1] = 0; target_ptr = (int *) target; source_ptr = (int *) source; set_2tree (PE_start, step, PE_size, &parent, &child_l, &child_r, my_pe); no_children = 0; build_tree (PE_start, step, PE_root, PE_size, &parent, &child_l, &child_r, my_pe); shmemi_trace (SHMEM_LOG_BROADCAST, "before broadcast, R_child = %d L_child = %d", child_r, child_l); /* The actual broadcast */ if (PE_size > 1) { if (my_pe == (PE_start + step * PE_root)) { pSync[0] = SHMEM_SYNC_VALUE; if (child_l != -1) { shmem_long_get (&lchild_ready, (const long *) &pSync[0], 1, child_l); while (lchild_ready != 0) shmem_long_get (&lchild_ready, &pSync[0], 1, child_l); shmem_int_put (target_ptr, source_ptr, nlong, child_l); shmem_fence (); shmem_long_put (&pSync[0], &is_ready, 1, child_l); no_children = 1; } if (child_r != -1) { shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); while (rchild_ready != 0) shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); shmem_int_put (target_ptr, source_ptr, nlong, child_r); shmem_fence (); shmem_long_put (&pSync[0], &is_ready, 1, child_r); no_children = 2; } shmem_long_wait_until (&pSync[1], SHMEM_CMP_EQ, (long) no_children); pSync[1] = SHMEM_SYNC_VALUE; } else { shmem_long_wait_until (&pSync[0], SHMEM_CMP_EQ, is_ready); pSync[0] = SHMEM_SYNC_VALUE; shmemi_trace (SHMEM_LOG_BROADCAST, "inside else"); memcpy (source_ptr, target_ptr, nlong * sizeof (int)); if (child_l != -1) { shmem_long_get (&lchild_ready, &pSync[0], 1, child_l); while (lchild_ready != 0) shmem_long_get (&lchild_ready, &pSync[0], 1, child_l); shmem_int_put (target_ptr, source_ptr, nlong, child_l); shmem_fence (); shmem_long_put (&pSync[0], &is_ready, 1, child_l); no_children = 1; } if (child_r != -1) { shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); while (rchild_ready != 0) shmem_long_get (&rchild_ready, &pSync[0], 1, child_r); shmem_int_put (target_ptr, source_ptr, nlong, child_r); shmem_fence (); shmem_long_put (&pSync[0], &is_ready, 1, child_r); no_children = 2; } pSync[0] = SHMEM_SYNC_VALUE; if (no_children == 0) { pSync[1] = SHMEM_SYNC_VALUE; /* TO DO: Is check for parents pSync required? */ shmem_long_inc (&pSync[1], parent); } else { shmem_long_wait_until (&pSync[1], SHMEM_CMP_EQ, (long) no_children); pSync[1] = SHMEM_SYNC_VALUE; /* printf("PE %d incrementing child count on PE %d\n",my_pe,parent); */ shmem_long_inc (&pSync[1], parent); } } shmemi_trace (SHMEM_LOG_BROADCAST, "at the end of bcast32"); /* shmem_barrier(PE_start, logPE_stride, PE_size, pSync); */ } }