Files
rocm-systems/src/misc/shmutils.cc
T

216 lines
7.6 KiB
C++
Raw Normal View History

2022-01-07 06:39:55 -08:00
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "shm.h"
2023-09-26 05:47:28 -07:00
#include "comm.h"
2022-01-07 06:39:55 -08:00
#include "checks.h"
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
2023-04-03 05:32:07 -07:00
#include <utils.h>
2022-01-07 06:39:55 -08:00
2022-11-29 04:27:46 -08:00
struct shmHandleInternal {
int fd;
char* shmPath;
char* shmPtr;
void* devShmPtr;
size_t shmSize;
size_t realShmSize;
int* refcount;
};
static void shmHandleInit(int fd, char* shmPath, size_t shmSize, size_t realShmSize, char* hptr, void* dptr, bool create, struct shmHandleInternal* handle) {
handle->fd = fd;
handle->shmPtr = hptr;
handle->devShmPtr = dptr;
handle->shmSize = shmSize;
handle->realShmSize = realShmSize;
2023-06-13 00:19:57 -07:00
handle->refcount = (hptr != NULL) ? (int*)(hptr + shmSize) : NULL;
2022-11-29 04:27:46 -08:00
if (create) {
int slen = strlen(shmPath);
handle->shmPath = (char*)malloc(slen + 1);
memcpy(handle->shmPath, shmPath, slen + 1);
if (hptr) memset(hptr, 0, shmSize);
} else {
handle->shmPath = NULL;
}
return;
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
ncclResult_t ncclShmOpen(char* shmPath, size_t shmSize, void** shmPtr, void** devShmPtr, int refcount, ncclShmHandle_t* handle) {
int fd = -1;
char* hptr = NULL;
void* dptr = NULL;
ncclResult_t ret = ncclSuccess;
struct shmHandleInternal* tmphandle;
bool create = refcount > 0 ? true : false;
const size_t refSize = sizeof(int); /* extra sizeof(int) bytes for reference count */
const size_t realShmSize = shmSize + refSize;
*handle = *shmPtr = NULL; /* assume shmPtr and handle always set correctly by users. */
2023-02-02 12:52:47 -08:00
EQCHECKGOTO(tmphandle = (struct shmHandleInternal*)calloc(1, sizeof(struct shmHandleInternal)), NULL, ret, fail);
2022-01-07 06:39:55 -08:00
if (create) {
2022-11-29 04:27:46 -08:00
/* refcount > 0 means the caller tries to allocate a shared memory. This shared memory segment will have
* refcount references; when the peer attaches, it should pass -1 to reduce one reference count. When it
* goes down to 0, unlink should be called in order to delete shared memory file. */
2022-01-07 06:39:55 -08:00
if (shmPath[0] == '\0') {
sprintf(shmPath, "/dev/shm/nccl-XXXXXX");
2024-06-11 01:28:01 -07:00
retry_mkstemp:
2022-11-29 04:27:46 -08:00
fd = mkstemp(shmPath);
2024-06-11 01:28:01 -07:00
if (fd < 0) {
if (errno == EINTR) {
INFO(NCCL_ALL, "mkstemp: Failed to create %s, error: %s (%d) - retrying", shmPath, strerror(errno), errno);
goto retry_mkstemp;
}
WARN("Error: failed to create shared memory file %p, error %s (%d)", shmPath, strerror(errno), errno);
ret = ncclSystemError;
goto fail;
}
2022-01-07 06:39:55 -08:00
} else {
2022-11-29 04:27:46 -08:00
SYSCHECKGOTO(fd = open(shmPath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), ret, fail);
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
2024-06-11 01:28:01 -07:00
retry_fallocate:
2023-09-26 05:47:28 -07:00
if (fallocate(fd, 0, 0, realShmSize) != 0) {
2024-06-11 01:28:01 -07:00
if (errno == EINTR) {
INFO(NCCL_ALL, "fallocate: Failed to extend %s to %ld bytes, error: %s (%d) - retrying", shmPath, realShmSize, strerror(errno), errno);
goto retry_fallocate;
}
WARN("Error: failed to extend %s to %ld bytes, error: %s (%d)", shmPath, realShmSize, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
ret = ncclSystemError;
goto fail;
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
INFO(NCCL_ALLOC, "Allocated %ld bytes of shared memory in %s", realShmSize, shmPath);
2022-01-07 06:39:55 -08:00
} else {
2022-11-29 04:27:46 -08:00
SYSCHECKGOTO(fd = open(shmPath, O_RDWR, S_IRUSR | S_IWUSR), ret, fail);
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
hptr = (char*)mmap(NULL, realShmSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (hptr == MAP_FAILED) {
2024-06-11 01:28:01 -07:00
WARN("Error: Could not map %s size %zu, error: %s (%d)", shmPath, realShmSize, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
ret = ncclSystemError;
2023-06-13 00:19:57 -07:00
hptr = NULL;
2022-11-29 04:27:46 -08:00
goto fail;
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
if (create) {
*(int*)(hptr + shmSize) = refcount;
} else {
2023-04-03 05:32:07 -07:00
int remref = ncclAtomicRefCountDecrement((int*)(hptr + shmSize));
2022-11-29 04:27:46 -08:00
if (remref == 0) {
/* the last peer has completed attachment, it should unlink the shm mem file. */
if (unlink(shmPath) != 0) {
2024-06-11 01:28:01 -07:00
INFO(NCCL_ALLOC, "unlink shared memory %s failed, error: %s (%d)", shmPath, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
}
}
}
2022-01-07 06:39:55 -08:00
if (devShmPtr) {
2022-11-29 04:27:46 -08:00
CUDACHECKGOTO(cudaHostRegister((void*)hptr, realShmSize, cudaHostRegisterMapped), ret, fail);
CUDACHECKGOTO(cudaHostGetDevicePointer(&dptr, (void*)hptr, 0), ret, fail);
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
shmHandleInit(fd, shmPath, shmSize, realShmSize, hptr, dptr, create, tmphandle);
exit:
*shmPtr = hptr;
if (devShmPtr) *devShmPtr = dptr;
*handle = (ncclShmHandle_t)tmphandle;
return ret;
fail:
2024-06-11 01:28:01 -07:00
WARN("Error while %s shared memory segment %s (size %ld), error: %s (%d)", create ? "creating" : "attaching to",
shmPath, shmSize, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
if (tmphandle) {
shmHandleInit(fd, shmPath, shmSize, realShmSize, hptr, dptr, create, tmphandle);
ncclShmClose((ncclShmHandle_t)tmphandle);
tmphandle = NULL;
}
hptr = NULL;
dptr = NULL;
goto exit;
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
ncclResult_t ncclShmClose(ncclShmHandle_t handle) {
ncclResult_t ret = ncclSuccess;
struct shmHandleInternal* tmphandle = (struct shmHandleInternal*)handle;
if (tmphandle) {
if (tmphandle->fd >= 0) {
close(tmphandle->fd);
2023-06-13 00:19:57 -07:00
if (tmphandle->shmPath != NULL && tmphandle->refcount != NULL && *tmphandle->refcount > 0) {
2022-11-29 04:27:46 -08:00
if (unlink(tmphandle->shmPath) != 0) {
2024-06-11 01:28:01 -07:00
WARN("unlink shared memory %s failed, error: %s (%d)", tmphandle->shmPath, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
ret = ncclSystemError;
}
}
2023-04-03 05:32:07 -07:00
free(tmphandle->shmPath);
2022-11-29 04:27:46 -08:00
}
if (tmphandle->shmPtr) {
if (tmphandle->devShmPtr) CUDACHECK(cudaHostUnregister(tmphandle->shmPtr));
if (munmap(tmphandle->shmPtr, tmphandle->realShmSize) != 0) {
2024-06-11 01:28:01 -07:00
WARN("munmap of shared memory %p size %ld failed, error: %s (%d)", tmphandle->shmPtr, tmphandle->realShmSize, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
ret = ncclSystemError;
}
}
free(tmphandle);
}
return ret;
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
ncclResult_t ncclShmUnlink(ncclShmHandle_t handle) {
ncclResult_t ret = ncclSuccess;
struct shmHandleInternal* tmphandle = (struct shmHandleInternal*)handle;
if (tmphandle) {
2024-06-11 01:28:01 -07:00
if (tmphandle->shmPath != NULL && tmphandle->refcount != NULL && *tmphandle->refcount > 0) {
2022-11-29 04:27:46 -08:00
if (unlink(tmphandle->shmPath) != 0) {
2024-06-11 01:28:01 -07:00
WARN("unlink shared memory %s failed, error: %s (%d)", tmphandle->shmPath, strerror(errno), errno);
2022-11-29 04:27:46 -08:00
ret = ncclSystemError;
}
free(tmphandle->shmPath);
tmphandle->shmPath = NULL;
2022-08-18 02:53:17 -07:00
}
2022-01-07 06:39:55 -08:00
}
2022-11-29 04:27:46 -08:00
return ret;
2022-01-07 06:39:55 -08:00
}
2023-09-26 05:47:28 -07:00
ncclResult_t ncclShmemAllgather(struct ncclComm *comm, struct ncclShmemCollBuff *shmem, void *sendbuff, void *recvbuff, size_t typeSize) {
ncclResult_t ret = ncclSuccess;
int curRound = shmem->round;
size_t mycnt;
2024-02-05 05:06:02 -08:00
if (comm == NULL || shmem == NULL || sendbuff == NULL || recvbuff == NULL || shmem->maxTypeSize < typeSize) {
2023-09-26 05:47:28 -07:00
ret = ncclInvalidArgument;
goto exit;
}
memcpy((char*)shmem->ptr[curRound] + comm->localRank * typeSize, sendbuff, typeSize);
/* sync among local ranks */
mycnt = __atomic_add_fetch(shmem->cnt[curRound], 1, __ATOMIC_ACQ_REL);
if (mycnt == comm->localRanks) {
*shmem->cnt[curRound ^ 1] = 0; /* prepare next round */
__atomic_store_n(shmem->cnt[curRound], comm->localRanks + 1, __ATOMIC_RELEASE); /* release everyone */
} else {
uint64_t t0 = clockNano();
while(__atomic_load_n(shmem->cnt[curRound], __ATOMIC_ACQUIRE) != comm->localRanks + 1) {
if (clockNano() - t0 >= 5 * 1000) sched_yield();
2024-06-11 01:28:01 -07:00
if (__atomic_load_n(comm->abortFlag, __ATOMIC_ACQUIRE) == 1) {
2023-09-26 05:47:28 -07:00
ret = ncclInternalError;
goto exit;
}
}
}
memcpy(recvbuff, (const void*)shmem->ptr[curRound], comm->localRanks * typeSize);
shmem->round ^= 1;
exit:
return ret;
}