/************************************************************************* * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. * * See LICENSE.txt for license information ************************************************************************/ #ifndef __COMMON_H__ #define __COMMON_H__ #define NCCL_TESTS_VERSION "2.18.3" #include "nccl.h" #if NCCL_VERSION_CODE >= NCCL_VERSION(2,28,0) #include "nccl_device.h" #endif #include #include #include #ifdef MPI_SUPPORT #include "mpi.h" #endif #include #include "nccl1_compat.h" #include "timer.h" // For nccl.h < 2.13 since we define a weak fallback extern "C" char const* ncclGetLastError(ncclComm_t comm); #define CUDACHECK(cmd) do { \ cudaError_t err = cmd; \ if( err != cudaSuccess ) { \ char hostname[1024]; \ getHostName(hostname, 1024); \ printf("%s: Test CUDA failure %s:%d '%s'\n", \ hostname, \ __FILE__,__LINE__,cudaGetErrorString(err)); \ return testCudaError; \ } \ } while(0) #if NCCL_VERSION_CODE >= NCCL_VERSION(2,13,0) #define NCCLCHECK(cmd) do { \ ncclResult_t res = cmd; \ if (res != ncclSuccess) { \ char hostname[1024]; \ getHostName(hostname, 1024); \ printf("%s: Test NCCL failure %s:%d " \ "'%s / %s'\n", \ hostname,__FILE__,__LINE__, \ ncclGetErrorString(res), \ ncclGetLastError(NULL)); \ return testNcclError; \ } \ } while(0) #else #define NCCLCHECK(cmd) do { \ ncclResult_t res = cmd; \ if (res != ncclSuccess) { \ char hostname[1024]; \ getHostName(hostname, 1024); \ printf("%s: Test NCCL failure %s:%d '%s'\n", \ hostname, \ __FILE__,__LINE__,ncclGetErrorString(res)); \ return testNcclError; \ } \ } while(0) #endif typedef enum { testSuccess = 0, testInternalError = 1, testCudaError = 2, testNcclError = 3, testTimeout = 4, testNotImplemented = 5, testInvalidUsage = 6, testNumResults = 7, // Must be last } testResult_t; // Relay errors up and trace #define TESTCHECK(cmd) do { \ testResult_t r = cmd; \ if (r!= testSuccess) { \ char hostname[1024]; \ getHostName(hostname, 1024); \ printf(" .. %s pid %d: Test failure %s:%d\n", \ hostname, getpid(), \ __FILE__,__LINE__); \ return r; \ } \ } while(0) struct testColl { const char name[20]; void (*getCollByteCount)( size_t *sendcount, size_t *recvcount, size_t *paramcount, size_t *sendInplaceOffset, size_t *recvInplaceOffset, size_t count, size_t eltSize, int nranks); testResult_t (*initData)(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root, int rep, int in_place); void (*getBw)(size_t count, int typesize, double sec, double* algBw, double* busBw, int nranks); testResult_t (*runColl)(void* sendbuff, size_t sendoffset, void* recvbuff, size_t recvoffset, size_t count, ncclDataType_t type, ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream, int implIndex); }; extern struct testColl allReduceTest; extern struct testColl allGatherTest; extern struct testColl reduceScatterTest; extern struct testColl broadcastTest; extern struct testColl reduceTest; extern struct testColl alltoAllTest; struct testEngine { void (*getBuffSize)(size_t *sendcount, size_t *recvcount, size_t count, int nranks); testResult_t (*runTest)(struct threadArgs* args, int root, ncclDataType_t type, const char* typeName, ncclRedOp_t op, const char* opName); #if NCCL_VERSION_CODE >= NCCL_VERSION(2,14,0) /* Optional; called from initComms after common fields are set on ncclConfig_t. */ void (*initCommConfig)(ncclConfig_t* config); #endif #if NCCL_VERSION_CODE >= NCCL_VERSION(2,29,0) testResult_t (*getDevCommRequirements)(int deviceImpl, ncclDevCommRequirements* reqs, ncclCommProperties_t* commProperties); #elif NCCL_VERSION_CODE >= NCCL_VERSION(2,28,0) bool (*getDevCommRequirements)(int deviceImpl, ncclDevCommRequirements* reqs); #endif }; extern struct testEngine ncclTestEngine; struct threadArgs { size_t nbytes; size_t minbytes; size_t maxbytes; size_t stepbytes; size_t stepfactor; int totalProcs; int nProcs; int proc; int nThreads; int thread; int nGpus; int* gpus; int localRank; void** sendbuffs; size_t sendBytes; size_t sendInplaceOffset; void** recvbuffs; size_t recvInplaceOffset; ncclUniqueId ncclId; ncclComm_t* comms; #if NCCL_VERSION_CODE >= NCCL_VERSION(2,28,0) ncclDevComm* devComms; #endif cudaStream_t* streams; void** expected; size_t expectedBytes; int* errors; double* bw; int* bw_count; int reportErrors; struct testColl* collTest; int64_t* initGpuMem; int64_t* bufferMemory; int64_t* devMemUsed; #if NCCL_VERSION_CODE >= NCCL_VERSION(2,19,0) void** sendRegHandles; void** recvRegHandles; #endif }; typedef testResult_t (*threadFunc_t)(struct threadArgs* args); struct testThread { pthread_t thread; threadFunc_t func; struct threadArgs args; testResult_t ret; }; // Provided by common.cu extern void Barrier(struct threadArgs* args); extern testResult_t TimeTest(struct threadArgs* args, ncclDataType_t type, const char* typeName, ncclRedOp_t op, const char* opName, int root); extern testResult_t InitDataReduce(void* data, const size_t count, const size_t offset, ncclDataType_t type, ncclRedOp_t op, const uint64_t seed, const int nranks); extern testResult_t InitData(void* data, const size_t count, size_t offset, ncclDataType_t type, ncclRedOp_t op, const uint64_t seed, const int nranks, const int rank); extern testResult_t AllocateBuffs(void **sendbuff, size_t sendBytes, void **recvbuff, size_t recvBytes, void **expected, size_t nbytes); #include static void getHostName(char* hostname, int maxlen) { gethostname(hostname, maxlen); for (int i=0; i< maxlen; i++) { if (hostname[i] == '\0') { return; } if (hostname[i] == '.') { hostname[i] = '\0'; return; } } } #include static uint64_t getHash(const char* string, size_t n) { // Based on DJB2a, result = result * 33 ^ char uint64_t result = 5381; for (size_t c = 0; c < n; c++) { result = ((result << 5) + result) ^ string[c]; } return result; } /* Generate a hash of the unique identifying string for this host * that will be unique for both bare-metal and container instances * Equivalent of a hash of; * * $(hostname)$(cat /proc/sys/kernel/random/boot_id) * */ #define HOSTID_FILE "/proc/sys/kernel/random/boot_id" static uint64_t getHostHash(const char* hostname) { char hostHash[1024]; // Fall back is the hostname if something fails (void) strncpy(hostHash, hostname, sizeof(hostHash)); int offset = strlen(hostHash); FILE *file = fopen(HOSTID_FILE, "r"); if (file != NULL) { char *p; if (fscanf(file, "%ms", &p) == 1) { strncpy(hostHash+offset, p, sizeof(hostHash)-offset-1); free(p); } } fclose(file); // Make sure the string is terminated hostHash[sizeof(hostHash)-1]='\0'; return getHash(hostHash, strlen(hostHash)); } #define HAVE_BF16 0 #define HAVE_FP8 0 #if NCCL_MAJOR >= 2 #if defined(__CUDA_BF16_TYPES_EXIST__) && NCCL_VERSION_CODE >= NCCL_VERSION(2,10,0) #undef HAVE_BF16 #define HAVE_BF16 1 #if defined(__CUDA_FP8_TYPES_EXIST__) && NCCL_VERSION_CODE >= NCCL_VERSION(2,24,0) #undef HAVE_FP8 #define HAVE_FP8 1 #endif #endif #endif static size_t wordSize(ncclDataType_t type) { switch(type) { case ncclChar: #if NCCL_MAJOR >= 2 //case ncclInt8: case ncclUint8: #endif #if HAVE_FP8 case ncclFloat8e4m3: case ncclFloat8e5m2: #endif return 1; case ncclHalf: #if HAVE_BF16 case ncclBfloat16: #endif //case ncclFloat16: return 2; case ncclInt: case ncclFloat: #if NCCL_MAJOR >= 2 //case ncclInt32: case ncclUint32: //case ncclFloat32: #endif return 4; case ncclInt64: case ncclUint64: case ncclDouble: //case ncclFloat64: return 8; default: return 0; } } extern int test_ncclVersion; // init'd with ncclGetVersion() extern int deviceCtaCount; // number of CTAs for device implementation constexpr int test_opNumMax = (int)ncclNumOps + (NCCL_VERSION_CODE >= NCCL_VERSION(2,11,0) ? 1 : 0); extern int test_opnum; extern int test_typenum; extern ncclDataType_t test_types[ncclNumTypes]; extern const char *test_typenames[ncclNumTypes]; extern ncclRedOp_t test_ops[]; extern const char *test_opnames[]; static int ncclstringtotype(char *str) { for (int t=0; t= NCCL_VERSION(2,28,0) template testResult_t testLaunchDeviceKernel(F kernel, void* sendbuff, size_t sendoffset, void* recvbuff, size_t recvoffset, size_t count, ncclDataType_t type, ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream) { if (kernel == nullptr) return testNotImplemented; ncclDevComm* devComm = (ncclDevComm*)comm; ncclWindow_t sendwin = (ncclWindow_t)sendbuff; ncclWindow_t recvwin = (ncclWindow_t)recvbuff; kernel<<>>(sendwin, sendoffset, recvwin, recvoffset, count, root, *devComm); return testSuccess; } #define SPECIALIZE_KERNEL(kernel, type, op) \ ( op != ncclSum ? nullptr : \ type == ncclInt8 ? kernel : \ type == ncclUint8 ? kernel : \ type == ncclInt32 ? kernel : \ type == ncclUint32 ? kernel : \ type == ncclInt64 ? kernel : \ type == ncclUint64 ? kernel : \ type == ncclFloat16 ? kernel : \ type == ncclFloat32 ? kernel : \ type == ncclFloat64 ? kernel : \ nullptr \ ) #else template testResult_t testLaunchDeviceKernel(F kernel, void* sendbuff, size_t sendoffset, void* recvbuff, size_t recvoffset, size_t count, ncclDataType_t type, ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream) { return testNotImplemented; } #define SPECIALIZE_KERNEL(kernel, type, op) nullptr #endif #endif