/** Lock a mutex. * * @param[in] hdl Mutex group that the mutex belongs to. * @param[in] mutex Desired mutex number [0..count-1] * @param[in] world_proc Absolute ID of process where the mutex lives */ void ARMCIX_Lock_hdl(armcix_mutex_hdl_t hdl, int mutex, int world_proc) { int rank, nproc, already_locked, i, proc; uint8_t *buf; ARMCII_Assert(mutex >= 0 && mutex < hdl->max_count); MPI_Comm_rank(hdl->grp.comm, &rank); MPI_Comm_size(hdl->grp.comm, &nproc); /* User gives us the absolute ID. Translate to the rank in the mutex's group. */ proc = ARMCII_Translate_absolute_to_group(&hdl->grp, world_proc); ARMCII_Assert(proc >= 0); buf = malloc(nproc*sizeof(uint8_t)); ARMCII_Assert(buf != NULL); buf[rank] = 1; /* Get all data from the lock_buf, except the byte belonging to * me. Set the byte belonging to me to 1. */ MPI_Win_lock(MPI_LOCK_EXCLUSIVE, proc, 0, hdl->windows[mutex]); MPI_Put(&buf[rank], 1, MPI_BYTE, proc, rank, 1, MPI_BYTE, hdl->windows[mutex]); /* Get data to the left of rank */ if (rank > 0) { MPI_Get(buf, rank, MPI_BYTE, proc, 0, rank, MPI_BYTE, hdl->windows[mutex]); } /* Get data to the right of rank */ if (rank < nproc - 1) { MPI_Get(&buf[rank+1], nproc-1-rank, MPI_BYTE, proc, rank + 1, nproc-1-rank, MPI_BYTE, hdl->windows[mutex]); } MPI_Win_unlock(proc, hdl->windows[mutex]); ARMCII_Assert(buf[rank] == 1); for (i = already_locked = 0; i < nproc; i++) if (buf[i] && i != rank) already_locked = 1; /* Wait for notification */ if (already_locked) { MPI_Status status; ARMCII_Dbg_print(DEBUG_CAT_MUTEX, "waiting for notification [proc = %d, mutex = %d]\n", proc, mutex); MPI_Recv(NULL, 0, MPI_BYTE, MPI_ANY_SOURCE, ARMCI_MUTEX_TAG+mutex, hdl->grp.comm, &status); } ARMCII_Dbg_print(DEBUG_CAT_MUTEX, "lock acquired [proc = %d, mutex = %d]\n", proc, mutex); free(buf); }
/** Check an I/O vector operation's buffers for overlap. * * @param[in] iov Vector of transfer information. * @return Logical true when regions overlap, 0 otherwise. */ int ARMCII_Iov_check_overlap(void **ptrs, int count, int size) { #ifndef NO_CHECK_OVERLAP #ifdef NO_USE_CTREE int i, j; if (ARMCII_GLOBAL_STATE.iov_checks_disabled) return 0; for (i = 0; i < count; i++) { for (j = i+1; j < count; j++) { const uint8_t *ptr_1_lo = ptrs[i]; const uint8_t *ptr_1_hi = ((uint8_t*)ptrs[i]) + size - 1; const uint8_t *ptr_2_lo = ptrs[j]; const uint8_t *ptr_2_hi = ((uint8_t*)ptrs[j]) + size - 1; if ( (ptr_1_lo >= ptr_2_lo && ptr_1_lo <= ptr_2_hi) || (ptr_1_hi >= ptr_2_lo && ptr_1_hi <= ptr_2_hi) || (ptr_1_lo < ptr_2_lo && ptr_1_hi > ptr_2_hi)) { ARMCII_Dbg_print(DEBUG_CAT_IOV, "IOV regions overlap: [%p, %p] - [%p, %p]\n", ptr_1_lo, ptr_1_hi, ptr_2_lo, ptr_2_hi); return 1; } } } #else int i; ctree_t ctree = CTREE_EMPTY; if (ARMCII_GLOBAL_STATE.iov_checks_disabled) return 0; for (i = 0; i < count; i++) { int conflict = ctree_insert(&ctree, ptrs[i], ((uint8_t*)ptrs[i]) + size - 1); if (conflict) { ctree_t cnode = ctree_locate(ctree, ptrs[i], ((uint8_t*)ptrs[i]) + size - 1); ARMCII_Dbg_print(DEBUG_CAT_IOV, "IOV regions overlap: [%p, %p] - [%p, %p]\n", ptrs[i], ((uint8_t*)ptrs[i]) + size - 1, cnode->lo, cnode->hi); ctree_destroy(&ctree); return 1; } } ctree_destroy(&ctree); #endif /* NO_USE_CTREE */ #endif /* NO_CHECK_OVERLAP */ return 0; }
/** Unlock a mutex. * * @param[in] hdl Mutex group that the mutex belongs to. * @param[in] mutex Desired mutex number [0..count-1] * @param[in] world_proc Absolute ID of process where the mutex lives */ void ARMCIX_Unlock_hdl(armcix_mutex_hdl_t hdl, int mutex, int world_proc) { int rank, nproc, i, proc; uint8_t *buf; ARMCII_Assert(mutex >= 0 && mutex < hdl->max_count); MPI_Comm_rank(hdl->grp.comm, &rank); MPI_Comm_size(hdl->grp.comm, &nproc); proc = ARMCII_Translate_absolute_to_group(&hdl->grp, world_proc); ARMCII_Assert(proc >= 0); buf = malloc(nproc*sizeof(uint8_t)); buf[rank] = 0; /* Get all data from the lock_buf, except the byte belonging to * me. Set the byte belonging to me to 0. */ MPI_Win_lock(MPI_LOCK_EXCLUSIVE, proc, 0, hdl->windows[mutex]); MPI_Put(&buf[rank], 1, MPI_BYTE, proc, rank, 1, MPI_BYTE, hdl->windows[mutex]); /* Get data to the left of rank */ if (rank > 0) { MPI_Get(buf, rank, MPI_BYTE, proc, 0, rank, MPI_BYTE, hdl->windows[mutex]); } /* Get data to the right of rank */ if (rank < nproc - 1) { MPI_Get(&buf[rank+1], nproc-1-rank, MPI_BYTE, proc, rank + 1, nproc-1-rank, MPI_BYTE, hdl->windows[mutex]); } MPI_Win_unlock(proc, hdl->windows[mutex]); ARMCII_Assert(buf[rank] == 0); /* Notify the next waiting process, starting to my right for fairness */ for (i = 1; i < nproc; i++) { int p = (rank + i) % nproc; if (buf[p] == 1) { ARMCII_Dbg_print(DEBUG_CAT_MUTEX, "notifying %d [proc = %d, mutex = %d]\n", p, proc, mutex); MPI_Send(NULL, 0, MPI_BYTE, p, ARMCI_MUTEX_TAG+mutex, hdl->grp.comm); break; } } ARMCII_Dbg_print(DEBUG_CAT_MUTEX, "lock released [proc = %d, mutex = %d]\n", proc, mutex); free(buf); }
/** Allocate a shared memory segment. Collective. * * @param[out] base_ptrs Array that will contain pointers to the base address of * each process' patch of the segment. Array is of length * equal to the number of processes in the group. * @param[in] size Number of bytes to allocate on the local process. */ int ARMCI_Malloc_group(void **base_ptrs, armci_size_t size, ARMCI_Group *group) { int i; gmr_t *mreg; ARMCII_Assert(PARMCI_Initialized()); mreg = gmr_create(size, base_ptrs, group); if (DEBUG_CAT_ENABLED(DEBUG_CAT_ALLOC)) { #define BUF_LEN 1000 char ptr_string[BUF_LEN]; int count = 0; if (mreg == NULL) { strncpy(ptr_string, "NULL", 5); } else { for (i = 0; i < mreg->nslices && count < BUF_LEN; i++) count += snprintf(ptr_string+count, BUF_LEN-count, (i == mreg->nslices-1) ? "%p" : "%p ", base_ptrs[i]); } ARMCII_Dbg_print(DEBUG_CAT_ALLOC, "base ptrs [%s]\n", ptr_string); #undef BUF_LEN } return 0; }
/** Free a shared memory allocation. Collective. * * @param[in] ptr Pointer to the local patch of the allocation */ int ARMCI_Free_group(void *ptr, ARMCI_Group *group) { gmr_t *mreg; if (ptr != NULL) { mreg = gmr_lookup(ptr, ARMCI_GROUP_WORLD.rank); ARMCII_Assert_msg(mreg != NULL, "Invalid shared pointer"); } else { ARMCII_Dbg_print(DEBUG_CAT_ALLOC, "given NULL\n"); mreg = NULL; } gmr_destroy(mreg, group); return 0; }