Update RCCL-tests in examples folder (#261)

- Create a local copy for ROCm/rccl-tests for our examples.
- Update argument parsing to no longer use getopt_long.
- Workaround for Dyninst instrumentation.

---------

Co-authored-by: David Galiffi <David.Galiffi@amd.com>

[ROCm/rocprofiler-systems commit: 4e5029221b]
Cette révision appartient à :
Pranjal Swarup
2025-06-27 11:44:13 -04:00
révisé par GitHub
Parent 0c91a0d8ed
révision 0497b7934f
26 fichiers modifiés avec 7330 ajouts et 13 suppressions
+36 -13
Voir le fichier
@@ -1,3 +1,25 @@
# MIT License
#
# Copyright (c) 2025 Advanced Micro Devices, Inc. All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
cmake_minimum_required(VERSION 3.18.4 FATAL_ERROR)
project(rocprofiler-systems-rccl-example LANGUAGES CXX)
@@ -28,7 +50,7 @@ function(rccl_message _MSG_TYPE)
endif()
endfunction()
find_package(hip HINTS ${ROCmVersion_DIR} PATHS ${ROCmVersion_DIR})
find_package(hip HINTS ${ROCmVersion_DIR} ${ROCM_PATH} /opt/rocm)
if(NOT hip_FOUND)
rccl_message(AUTHOR_WARNING "${PROJECT_NAME} skipped. Missing HIP...")
@@ -39,9 +61,10 @@ if(
"${CMAKE_PROJECT_NAME}" STREQUAL "rocprofiler-systems"
AND ("$ENV{ROCPROFSYS_CI}" OR ROCPROFSYS_CI OR ROCPROFSYS_BUILD_CI)
)
find_package(rccl QUIET) # avoid generating warning in CI
# avoid generating warning in CI
find_package(rccl HINTS ${ROCmVersion_DIR} ${ROCM_PATH} /opt/rocm QUIET)
else()
find_package(rccl)
find_package(rccl HINTS ${ROCmVersion_DIR} ${ROCM_PATH} /opt/rocm)
endif()
if(NOT rccl_FOUND)
@@ -50,19 +73,22 @@ if(NOT rccl_FOUND)
endif()
if(hip_FOUND AND rccl_FOUND)
include(FetchContent)
FetchContent_Declare(rccl-tests GIT_REPOSITORY https://github.com/ROCm/rccl-tests.git)
# Use existing rccl-tests source in the project binary directory
set(rccl-tests_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rccl-tests")
set(rccl-tests_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/rccl-tests")
file(COPY ${rccl-tests_SOURCE_DIR}/ DESTINATION ${rccl-tests_BUILD_DIR})
# After the following call, the CMake targets defined by googletest and Catch2 will be
# available to the rest of the build
FetchContent_Populate(rccl-tests)
if(NOT EXISTS "${rccl-tests_SOURCE_DIR}")
rccl_message(AUTHOR_WARNING "${PROJECT_NAME} skipped. Missing rccl-tests source at ${rccl-tests_SOURCE_DIR}")
return()
endif()
get_filename_component(rccl_ROOT_DIR "${rccl_INCLUDE_DIR}" DIRECTORY)
rccl_message(STATUS "Building rccl-tests...")
execute_process(
COMMAND make HIP_HOME=${ROCM_PATH} RCCL_HOME=${rccl_ROOT_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/_deps/rccl-tests-src
WORKING_DIRECTORY ${rccl-tests_BUILD_DIR}
RESULT_VARIABLE _RCCL_BUILD_RET
ERROR_VARIABLE _RCCL_BUILD_ERR
OUTPUT_VARIABLE _RCCL_BUILD_OUT
@@ -74,10 +100,7 @@ if(hip_FOUND AND rccl_FOUND)
rccl_message(${_RCCL_BUILD_OUT})
rccl_message(AUTHOR_WARNING "Failed to build rccl-tests: ${_RCCL_BUILD_ERR}")
else()
file(
GLOB RCCL_TEST_EXECUTABLES
${CMAKE_BINARY_DIR}/_deps/rccl-tests-src/build/*_perf
)
file(GLOB RCCL_TEST_EXECUTABLES ${rccl-tests_BUILD_DIR}/build/*_perf)
set(_RCCL_TEST_TARGETS)
foreach(_EXE ${RCCL_TEST_EXECUTABLES})
+23
Voir le fichier
@@ -0,0 +1,23 @@
#
# Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
#
# See LICENCE.txt for license information
#
BUILDDIR ?= build
override BUILDDIR := $(abspath $(BUILDDIR))
.PHONY: all clean
default: src.build
TARGETS=src
all: ${TARGETS:%=%.build}
clean: ${TARGETS:%=%.clean}
%.build:
${MAKE} -C $* build BUILDDIR=${BUILDDIR}
%.clean:
${MAKE} -C $* clean BUILDDIR=${BUILDDIR}
+174
Voir le fichier
@@ -0,0 +1,174 @@
#
# Copyright (c) 2015-2022, NVIDIA CORPORATION. All rights reserved.
# Modifications are Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved.
#
# See LICENSE.txt for license information
#
ROCM_PATH ?= /opt/rocm
MPI_HOME ?= /usr/lib/x86_64-linux-gnu
PREFIX ?= /usr/local
VERBOSE ?= 0
DEBUG ?= 0
NCCL_HOME ?= ""
CUSTOM_RCCL_LIB ?= ""
HIPCC ?= $(ROCM_PATH)/bin/amdclang++
HIPCONFIG = $(ROCM_PATH)/bin/hipconfig
CXX = $(HIPCC)
HIPCUFLAGS := -std=c++14
LDFLAGS :=
HIPLDFLAGS :=
HIP_VERSION = $(strip $(shell which $(HIPCONFIG) >/dev/null && $(HIPCONFIG) --version))
HIP_MAJOR = $(shell echo $(HIP_VERSION) | cut -d "." -f 1)
HIP_MINOR = $(shell echo $(HIP_VERSION) | cut -d "." -f 2)
# Better define GPU_TARGETS in your environment to the minimal set
# of archs to reduce compile time.
# Currently, supports gfx906,gfx908,gfx90a,gfx942,gfx950,gfx1030,gfx1100,gfx1101,gfx1102,gfx1200,gfx1201
ifndef GPU_TARGETS
GPU_TARGETS = gfx906 gfx908 gfx90a
ifeq ($(shell test "0$(HIP_MAJOR)" -eq 6; echo $$?),0)
# Include gfx942 support if we're using ROCm 6.0 or above
GPU_TARGETS += gfx942
ifeq ($(shell test "0$(HIP_MINOR)" -ge 5; echo $$?),0)
# Include gfx950 support if we're using ROCm 6.5 or above
GPU_TARGETS += gfx950
endif
endif
GPU_TARGETS += gfx1030 gfx1100 gfx1101 gfx1102 gfx1200 gfx1201
endif
GPU_TARGETS_FLAGS = $(foreach target,$(GPU_TARGETS),"--offload-arch=$(target)")
#CUDA_VERSION = $(strip $(shell which $(NVCC) >/dev/null && $(NVCC) --version | grep release | sed 's/.*release //' | sed 's/\,.*//'))
#CUDA_MAJOR = $(shell echo $(CUDA_VERSION) | cut -d "." -f 1)
#CUDA_MINOR = $(shell echo $(CUDA_VERSION) | cut -d "." -f 2)
#
## Better define NVCC_GENCODE in your environment to the minimal set
## of archs to reduce compile time.
#ifeq ($(shell test "0$(CUDA_MAJOR)" -eq 12 -a "0$(CUDA_MINOR)" -ge 8 -o "0$(CUDA_MAJOR)" -ge 13; echo $$?),0)
## Include Blackwell support if we're using CUDA12.8 or above
#NVCC_GENCODE ?= -gencode=arch=compute_80,code=sm_80 \
# -gencode=arch=compute_90,code=sm_90 \
# -gencode=arch=compute_100,code=sm_100 \
# -gencode=arch=compute_120,code=sm_120 \
# -gencode=arch=compute_120,code=compute_120
#else ifeq ($(shell test "0$(CUDA_MAJOR)" -ge 12; echo $$?),0)
#NVCC_GENCODE ?= -gencode=arch=compute_60,code=sm_60 \
# -gencode=arch=compute_61,code=sm_61 \
# -gencode=arch=compute_70,code=sm_70 \
# -gencode=arch=compute_80,code=sm_80 \
# -gencode=arch=compute_90,code=sm_90 \
# -gencode=arch=compute_90,code=compute_90
#else ifeq ($(shell test "0$(CUDA_MAJOR)" -ge 11; echo $$?),0)
#NVCC_GENCODE ?= -gencode=arch=compute_60,code=sm_60 \
# -gencode=arch=compute_61,code=sm_61 \
# -gencode=arch=compute_70,code=sm_70 \
# -gencode=arch=compute_80,code=sm_80 \
# -gencode=arch=compute_80,code=compute_80
#else
#NVCC_GENCODE ?= -gencode=arch=compute_35,code=sm_35 \
# -gencode=arch=compute_50,code=sm_50 \
# -gencode=arch=compute_60,code=sm_60 \
# -gencode=arch=compute_61,code=sm_61 \
# -gencode=arch=compute_70,code=sm_70 \
# -gencode=arch=compute_70,code=compute_70
#endif
ifneq ($(NCCL_HOME), "")
HIPCUFLAGS += -I$(NCCL_HOME)/ -I$(NCCL_HOME)/include
HIPLDFLAGS += -Wl,-rpath,$(NCCL_HOME) -L$(NCCL_HOME) -L$(NCCL_HOME)/lib
endif
HIPCUFLAGS += -I$(ROCM_PATH)/include
HIPCUFLAGS += -I$(ROCM_PATH)/include/hip
HIPCUFLAGS += -x hip -D__HIP_PLATFORM_AMD__ -D__HIPCC__ $(GPU_TARGETS_FLAGS)
LDFLAGS += -L$(ROCM_PATH)/lib -lhsa-runtime64 -lrt
ifneq ($(CUSTOM_RCCL_LIB), "")
HIPLDFLAGS += -L$(CUSTOM_RCCL_LIB)
endif
HIPLDFLAGS += -L$(ROCM_PATH)/lib -lhsa-runtime64 -lamdhip64 -lstdc++ -lrt -pthread
ifeq ($(DEBUG), 0)
HIPCUFLAGS += -O3
else
HIPCUFLAGS += -O0 -g -ggdb3
endif
ifeq ($(VERBOSE), 0)
.SILENT:
endif
.PHONY: build clean
BUILDDIR ?= ../build
HIPIFY_DIR ?= $(BUILDDIR)/hipify
.PRECIOUS: $(HIPIFY_DIR)/%.cpp $(HIPIFY_DIR)/%.h
ifeq ($(MPI), 1)
HIPCUFLAGS += -DMPI_SUPPORT -I${MPI_HOME}/include -I${MPI_HOME}/include/openmpi -I${MPI_HOME}/openmpi/include -I${MPI_HOME}/openmpi/include/openmpi
HIPLDFLAGS += -L${MPI_HOME}/lib -L${MPI_HOME}/openmpi/lib -lmpi
else ifeq ($(MPICH), 1)
HIPCUFLAGS += -DMPI_SUPPORT -I${MPI_HOME}/include -I${MPI_HOME}/mpich/include -I/usr/include/x86_64-linux-gnu/mpich
HIPLDFLAGS += -L${MPI_HOME}/lib -L${MPI_HOME}/mpich/lib -lmpich
endif
LIBRARIES += rccl
HIPLDFLAGS += $(LIBRARIES:%=-l%)
DST_DIR := $(BUILDDIR)
SRC_FILES := $(wildcard *.cpp)
OBJ_FILES := $(SRC_FILES:%.cpp=${DST_DIR}/%.o)
BIN_FILES_LIST := all_reduce all_gather broadcast reduce_scatter reduce alltoall scatter gather sendrecv alltoallv
BIN_FILES := $(BIN_FILES_LIST:%=${DST_DIR}/%_perf)
GIT_VERSION_FILE := ${DST_DIR}/src/git_version.cpp
GIT_REV := $(shell git log --pretty=format:'%h' -n 1)
GIT_DIFF := $(shell git diff --quiet --exit-code || echo +)
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
build: ${BIN_FILES}
clean:
rm -rf ${DST_DIR}
TEST_VERIFIABLE_SRCDIR := ../verifiable
TEST_VERIFIABLE_BUILDDIR := $(BUILDDIR)/verifiable
include ../verifiable/verifiable.mk
# Rule to create git_version.cpp
$(GIT_VERSION_FILE):
@mkdir -p ${DST_DIR}/src
@echo 'const char* rcclTestsGitHash = "$(GIT_BRANCH):$(GIT_REV)$(GIT_DIFF)";' > $@
${HIPIFY_DIR}/%.cpp: %.cpp
@printf "Hipifying %-35s > %s\n" $< $@
@mkdir -p ${HIPIFY_DIR}
hipify-perl -quiet-warnings $< > $@
${HIPIFY_DIR}/%.h: %.h
@printf "Hipifying %-35s > %s\n" $< $@
@mkdir -p ${HIPIFY_DIR}
hipify-perl -quiet-warnings $< > $@
${DST_DIR}/%.o: ${HIPIFY_DIR}/%.cpp ${HIPIFY_DIR}/common.h $(TEST_VERIFIABLE_HDRS) $(GIT_VERSION_FILE)
@printf "Compiling %-35s > %s\n" $< $@
@mkdir -p ${DST_DIR}
echo "$(HIPCC) $(HIPCUFLAGS) -I. -c -o $@ $<"
$(HIPCC) $(HIPCUFLAGS) -I. -c -o $@ $<
${DST_DIR}/timer.o: timer.cc timer.h
@printf "Compiling %-35s > %s\n" $< $@
@mkdir -p ${DST_DIR}
$(CXX) $(CXXFLAGS) -o $@ -c timer.cc
${DST_DIR}/%_perf:${DST_DIR}/%.o ${DST_DIR}/common.o ${DST_DIR}/timer.o $(TEST_VERIFIABLE_OBJS) $(DST_DIR)/src/git_version.cpp
@printf "Linking %-35s > %s\n" $< $@
@mkdir -p ${DST_DIR}
echo "$(HIPCC) -o $@ $^ $(HIPLDFLAGS)"
$(HIPCC) -o $@ $^ $(HIPLDFLAGS)
+110
Voir le fichier
@@ -0,0 +1,110 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
AllGatherGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
size_t base = (count / nranks) & -(16 / eltSize);
*sendcount = base;
*recvcount = base * nranks;
*sendInplaceOffset = base;
*recvInplaceOffset = 0;
*paramcount = base;
}
testResult_t
AllGatherInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? ((char*) args->recvbuffs[i]) + rank * args->sendBytes
: args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, ncclSum, 33 * rep + rank, 1, 0));
for(int j = 0; j < nranks; j++)
{
TESTCHECK(InitData((char*) args->expected[i] + args->sendBytes * j, sendcount,
0, type, ncclSum, 33 * rep + j, 1, 0));
}
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
AllGatherGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize * nranks) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (nranks - 1)) / ((double) nranks);
*busBw = baseBw * factor;
}
testResult_t
AllGatherRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
NCCLCHECK(ncclAllGather(sendbuff, recvbuff, count, type, comm, stream));
return testSuccess;
}
struct testColl allGatherTest = { "AllGather", AllGatherGetCollByteCount,
AllGatherInitData, AllGatherGetBw, AllGatherRunColl };
void
AllGatherGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
AllGatherGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
AllGatherRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &allGatherTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
for(int i = 0; i < type_count; i++)
{
TESTCHECK(
TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0, "none", -1));
}
return testSuccess;
}
struct testEngine ncclTestEngine = { AllGatherGetBuffSize, AllGatherRunTest };
+126
Voir le fichier
@@ -0,0 +1,126 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
AllReduceGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
*sendcount = count;
*recvcount = count;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
*paramcount = *sendcount;
}
testResult_t
AllReduceInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, op, rep, nranks, rank));
TESTCHECK(InitDataReduce(args->expected[i], recvcount, 0, type, op, rep, nranks));
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
AllReduceGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (2 * (nranks - 1))) / ((double) nranks);
*busBw = baseBw * factor;
}
testResult_t
AllReduceRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
NCCLCHECK(ncclAllReduce(sendbuff, recvbuff, count, type, op, comm, stream));
return testSuccess;
}
struct testColl allReduceTest = { "AllReduce", AllReduceGetCollByteCount,
AllReduceInitData, AllReduceGetBw, AllReduceRunColl };
void
AllReduceGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
AllReduceGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
AllReduceRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &allReduceTest;
ncclDataType_t* run_types;
ncclRedOp_t* run_ops;
const char ** run_typenames, **run_opnames;
int type_count, op_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if((int) op != -1)
{
op_count = 1;
run_ops = &op;
run_opnames = &opName;
}
else
{
op_count = test_opnum;
run_ops = test_ops;
run_opnames = test_opnames;
}
for(int i = 0; i < type_count; i++)
{
for(int j = 0; j < op_count; j++)
{
#if defined(RCCL_FLOAT8)
if((run_types[i] == ncclFp8E4M3 || run_types[i] == ncclFp8E5M2) &&
run_ops[j] == ncclProd)
continue;
#endif
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], run_ops[j],
run_opnames[j], -1));
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { AllReduceGetBuffSize, AllReduceRunTest };
+112
Voir le fichier
@@ -0,0 +1,112 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
AlltoAllGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
*paramcount = (count / nranks) & -(16 / eltSize);
*sendcount = nranks * (*paramcount);
*recvcount = *sendcount;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
}
testResult_t
AlltoAllInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, ncclSum, 33 * rep + rank, 1, 0));
for(int j = 0; j < nranks; j++)
{
size_t partcount = sendcount / nranks;
TESTCHECK(InitData((char*) args->expected[i] + j * partcount * wordSize(type),
partcount, rank * partcount, type, ncclSum, 33 * rep + j,
1, 0));
}
CUDACHECK(cudaDeviceSynchronize());
}
// We don't support in-place alltoall
args->reportErrors = in_place ? 0 : 1;
return testSuccess;
}
void
AlltoAllGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * nranks * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (nranks - 1)) / ((double) (nranks));
*busBw = baseBw * factor;
}
testResult_t
AlltoAllRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
NCCLCHECK(ncclAllToAll(sendbuff, recvbuff, count, type, comm, stream));
return testSuccess;
}
struct testColl alltoAllTest = { "AlltoAll", AlltoAllGetCollByteCount, AlltoAllInitData,
AlltoAllGetBw, AlltoAllRunColl };
void
AlltoAllGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
AlltoAllGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
AlltoAllRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &alltoAllTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
for(int i = 0; i < type_count; i++)
{
TESTCHECK(
TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0, "none", -1));
}
return testSuccess;
}
struct testEngine ncclTestEngine = { AlltoAllGetBuffSize, AlltoAllRunTest };
+218
Voir le fichier
@@ -0,0 +1,218 @@
/*************************************************************************
* Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
#define USE_RCCL_GATHER_SCATTER
void
AlltoAllvGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
if(count < nranks * nranks / 2)
{
*sendcount = 0;
*recvcount = 0;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
*paramcount = 0;
}
else
{
*paramcount = (count / nranks) & -(16 / eltSize);
*sendcount = nranks * (*paramcount);
*recvcount = *sendcount;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
}
}
testResult_t
AlltoAllvInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, ncclSum, 33 * rep + rank, 1, 0));
#if 0
int *dataHost = (int *)malloc(args->sendBytes);
cudaMemcpy(dataHost, data, args->sendBytes, cudaMemcpyDeviceToHost);
printf(" Rank [%d] Original: ", rank);
for(int j=0; j<sendcount; j++) {
printf("%d:%d ", j, dataHost[j]);
}
printf("\n");
free(dataHost);
#endif
size_t rdisp = 0;
size_t data_count = sendcount * 2 / nranks;
size_t chunksize = data_count / nranks;
for(int j = 0; j < nranks; j++)
{
size_t scount = 0, rcount = ((j + rank) % nranks) * chunksize;
if((j + rank) % nranks == 0)
rcount += (sendcount - chunksize * (nranks - 1) * nranks / 2);
size_t sdisp = 0;
for(int k = 0; k < nranks; k++)
{
scount = ((k + j) % nranks) * chunksize;
if((k + j) % nranks == 0)
scount += (sendcount - chunksize * (nranks - 1) * nranks / 2);
if(k == rank) break;
sdisp += scount;
}
TESTCHECK(InitData(((char*) args->expected[i]) + rdisp * wordSize(type),
rcount, sdisp, type, ncclSum, 33 * rep + j, 1, 0));
rdisp += rcount;
}
CUDACHECK(cudaDeviceSynchronize());
}
// We don't support in-place alltoall
args->reportErrors = in_place ? 0 : 1;
return testSuccess;
}
void
AlltoAllvGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * nranks * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (nranks - 1)) / ((double) (nranks));
*busBw = baseBw * factor;
}
testResult_t
AlltoAllvRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
int nranks;
NCCLCHECK(ncclCommCount(comm, &nranks));
int rank;
NCCLCHECK(ncclCommUserRank(comm, &rank));
if(count == 0) return testSuccess;
size_t *sendcounts, *recvcounts, *sdispls, *rdispls;
sendcounts = (size_t*) malloc(nranks * nranks * sizeof(size_t));
recvcounts = (size_t*) malloc(nranks * nranks * sizeof(size_t));
sdispls = (size_t*) malloc(nranks * nranks * sizeof(size_t));
rdispls = (size_t*) malloc(nranks * nranks * sizeof(size_t));
if(sendcounts == nullptr || recvcounts == nullptr || sdispls == nullptr ||
rdispls == nullptr)
{
printf("failed to allocate buffers for alltoallv\n");
return testNcclError;
}
size_t disp = 0;
size_t chunksize = count * 2 / nranks;
for(int i = 0; i < nranks; i++)
{
size_t scount = ((i + rank) % nranks) * chunksize;
if((i + rank) % nranks == 0)
scount += (count * nranks - chunksize * (nranks - 1) * nranks / 2);
sendcounts[i + rank * nranks] = recvcounts[i + rank * nranks] = scount;
sdispls[i + rank * nranks] = rdispls[i + rank * nranks] = disp;
disp += scount;
// printf("%d->%d: sendcounts/recvcounts %lx sdispls/rdispls %lx\n", rank, i,
// sendcounts[i+rank*nranks]*wordSize(type),
// sdispls[i+rank*nranks]*wordSize(type));
}
#if NCCL_MAJOR < 2 || NCCL_MINOR < 7
printf(
"NCCL 2.7 or later is needed for alltoallv. This test was compiled with %d.%d.\n",
NCCL_MAJOR, NCCL_MINOR);
return testNcclError;
#else
# if defined(RCCL_ALLTOALLV) && defined(USE_RCCL_GATHER_SCATTER)
NCCLCHECK(ncclAllToAllv(sendbuff, sendcounts + rank * nranks, sdispls + rank * nranks,
recvbuff, recvcounts + rank * nranks, rdispls + rank * nranks,
type, comm, stream));
# else
NCCLCHECK(ncclGroupStart());
for(int r = 0; r < nranks; r++)
{
if(sendcounts[r + rank * nranks] != 0)
{
NCCLCHECK(
ncclSend(((char*) sendbuff) + sdispls[r + rank * nranks] * wordSize(type),
sendcounts[r + rank * nranks], type, r, comm, stream));
}
if(recvcounts[r + rank * nranks] != 0)
{
NCCLCHECK(
ncclRecv(((char*) recvbuff) + rdispls[r + rank * nranks] * wordSize(type),
recvcounts[r + rank * nranks], type, r, comm, stream));
}
}
NCCLCHECK(ncclGroupEnd());
# endif
#endif
free(sendcounts);
free(recvcounts);
free(sdispls);
free(rdispls);
return testSuccess;
}
struct testColl alltoAllTest = { "AlltoAllv", AlltoAllvGetCollByteCount,
AlltoAllvInitData, AlltoAllvGetBw, AlltoAllvRunColl };
void
AlltoAllvGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
AlltoAllvGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
AlltoAllvRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &alltoAllTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = ncclNumTypes;
run_types = test_types;
run_typenames = test_typenames;
}
for(int i = 0; i < type_count; i++)
{
TESTCHECK(
TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0, "", -1));
}
return testSuccess;
}
struct testEngine ncclTestEngine = { AlltoAllvGetBuffSize, AlltoAllvRunTest };
+131
Voir le fichier
@@ -0,0 +1,131 @@
/*************************************************************************
* Copyright (c) 2015-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
BroadcastGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
*sendcount = count;
*recvcount = count;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
*paramcount = *sendcount;
}
testResult_t
BroadcastInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
if(rank == root)
TESTCHECK(InitData(data, sendcount, 0, type, ncclSum, rep, 1, 0));
TESTCHECK(InitData(args->expected[i], recvcount, 0, type, ncclSum, rep, 1, 0));
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
BroadcastGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = 1;
*busBw = baseBw * factor;
}
testResult_t
BroadcastRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
int rank;
NCCLCHECK(ncclCommUserRank(comm, &rank));
#if NCCL_MAJOR >= 2 && NCCL_MINOR >= 2
NCCLCHECK(ncclBroadcast(sendbuff, recvbuff, count, type, root, comm, stream));
#else
if(rank == root)
{
NCCLCHECK(ncclBcast(sendbuff, count, type, root, comm, stream));
}
else
{
NCCLCHECK(ncclBcast(recvbuff, count, type, root, comm, stream));
}
#endif
return testSuccess;
}
struct testColl broadcastTest = { "Broadcast", BroadcastGetCollByteCount,
BroadcastInitData, BroadcastGetBw, BroadcastRunColl };
void
BroadcastGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
BroadcastGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
BroadcastRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &broadcastTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
int begin_root, end_root;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if(root != -1)
{
begin_root = end_root = root;
}
else
{
begin_root = 0;
end_root = args->nProcs * args->nThreads * args->nGpus - 1;
}
for(int i = 0; i < type_count; i++)
{
for(int j = begin_root; j <= end_root; j++)
{
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0,
"none", j));
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { BroadcastGetBuffSize, BroadcastRunTest };
Fichier diff supprimé car celui-ci est trop grand Voir la Diff
+431
Voir le fichier
@@ -0,0 +1,431 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
* Modifications Copyright (c) Microsoft Corporation. Licensed under the MIT License.
*
* See LICENSE.txt for license information
************************************************************************/
#ifndef __COMMON_H__
#define __COMMON_H__
#include "rccl/rccl.h"
#include <algorithm>
#include <cstdint>
#include <stdio.h>
#ifdef MPI_SUPPORT
# include "mpi.h"
#endif
#include "nccl1_compat.h"
#include "timer.h"
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <string>
// Ensures backward compatibility for FP8 types in RCCL 2.24.3 and later
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 24, 3)
# define ncclFp8E4M3 ncclFloat8e4m3
# define ncclFp8E5M2 ncclFloat8e5m2
#endif
// 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,
testNumResults = 5
} 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, void* recvbuff, size_t count,
ncclDataType_t type, ncclRedOp_t op, int root,
ncclComm_t comm, cudaStream_t stream);
};
extern struct testColl allReduceTest;
extern struct testColl allGatherTest;
extern struct testColl reduceScatterTest;
extern struct testColl broadcastTest;
extern struct testColl reduceTest;
extern struct testColl alltoAllTest;
class Reporter
{
public:
Reporter(std::string fileName, std::string outputFormat);
~Reporter()
{
if(_outputValid)
{
_out.close();
}
};
void setParameters(const size_t numCycle, const char* name, const char* typeName,
const char* opName);
void addResult(int gpusPerRank, int ranksPerNode, int totalRanks, size_t numBytes,
int inPlace, double timeUsec, double algBw, double busBw,
int64_t wrongElts = -1);
private:
bool isMainThread();
template <typename T>
std::pair<std::string, std::string> makeValueKeyPair(T v, std::string k)
{
return std::make_pair(std::to_string(v), k);
};
template <>
std::pair<std::string, std::string> makeValueKeyPair<std::string>(std::string v,
std::string k)
{
return std::make_pair("\"" + v + "\"", k);
};
bool _outputValid = false;
std::ofstream _out;
std::string _outputFormat;
size_t _numCycle = 0;
std::string _collectiveName;
std::string _typeName;
std::string _opName;
};
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);
};
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;
int enable_out_of_place;
int enable_in_place;
int enable_cache_flush;
int enable_rotating_tensor;
void** sendbuffs;
size_t sendBytes;
size_t sendInplaceOffset;
void** recvbuffs;
size_t recvInplaceOffset;
ncclUniqueId ncclId;
ncclComm_t* comms;
cudaStream_t* streams;
void** expected;
size_t expectedBytes;
int* errors;
double* bw;
int* bw_count;
int reportErrors;
struct testColl* collTest;
Reporter* reporter;
};
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 void
AllocateBuffs(void** sendbuff, void** recvbuff, void** expected, void** expectedHost,
size_t nbytes, int nranks);
#include <unistd.h>
static void
getHostName(char* hostname, int maxlen)
{
gethostname(hostname, maxlen);
for(int i = 0; i < maxlen; i++)
{
if(hostname[i] == '.')
{
hostname[i] = '\0';
return;
}
}
}
#include <stdint.h>
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));
}
static size_t
wordSize(ncclDataType_t type)
{
switch(type)
{
case ncclChar:
#if NCCL_MAJOR >= 2
// case ncclInt8:
case ncclUint8:
# if NCCL_MAJOR >= 2 && RCCL_FLOAT8 == 1
case ncclFp8E4M3:
case ncclFp8E5M2:
# endif
#endif
return 1;
case ncclHalf:
#if NCCL_MAJOR >= 2 && RCCL_BFLOAT16 == 1
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()
typedef enum
{
ncclCoarse = 0,
ncclFine = 1,
ncclHost = 2,
ncclManaged = 3,
nccl_NUM_MTYPES = 4
} ncclMemoryType_t;
extern const char* test_memorytypes[nccl_NUM_MTYPES];
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 < test_typenum; t++)
{
if(strcmp(str, test_typenames[t]) == 0)
{
return t;
}
}
if(strcmp(str, "all") == 0)
{
return -1;
}
printf("invalid type %s, defaulting to %s .. \n", str, test_typenames[ncclFloat]);
return ncclFloat;
}
static int
ncclstringtoop(char* str)
{
for(int o = 0; o < test_opnum; o++)
{
if(strcmp(str, test_opnames[o]) == 0)
{
return o;
}
}
if(strcmp(str, "all") == 0)
{
return -1;
}
printf("invalid op %s, defaulting to %s .. \n", str, test_opnames[ncclSum]);
return ncclSum;
}
static int
ncclstringtoroot(char* str)
{
if(strcmp(str, "all") == 0)
{
return -1;
}
return strtol(str, NULL, 0);
}
static int
ncclstringtomtype(char* str)
{
for(int o = 0; o < nccl_NUM_MTYPES; o++)
{
if(strcmp(str, test_memorytypes[o]) == 0)
{
return o;
}
}
printf("invalid memorytype %s, defaulting to %s .. \n", str,
test_memorytypes[ncclCoarse]);
return ncclCoarse;
}
extern int is_main_proc;
extern thread_local int is_main_thread;
#define PRINT \
if(is_main_thread) printf
#endif
+143
Voir le fichier
@@ -0,0 +1,143 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
GatherGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset, size_t count,
size_t eltSize, int nranks)
{
*sendcount = (count / nranks) & -(16 / eltSize);
*recvcount = (*sendcount) * nranks;
*sendInplaceOffset = *sendcount;
*recvInplaceOffset = 0;
*paramcount = *sendcount;
}
testResult_t
GatherInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? ((char*) args->recvbuffs[i]) + rank * args->sendBytes
: args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, rank * sendcount, type, ncclSum, rep, 1, 0));
CUDACHECK(cudaMemcpy(args->expected[i], args->recvbuffs[i], args->expectedBytes,
cudaMemcpyDefault));
if(rank == root)
{
TESTCHECK(InitData(args->expected[i], nranks * sendcount, 0, type, ncclSum,
rep, 1, 0));
}
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
GatherGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * nranks * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (nranks - 1)) / ((double) (nranks));
*busBw = baseBw * factor;
}
testResult_t
GatherRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
int nRanks;
NCCLCHECK(ncclCommCount(comm, &nRanks));
int rank;
NCCLCHECK(ncclCommUserRank(comm, &rank));
size_t rankOffset = count * wordSize(type);
if(count == 0) return testSuccess;
NCCLCHECK(ncclGroupStart());
NCCLCHECK(ncclSend(sendbuff, count, type, root, comm, stream));
if(rank == root)
{
for(int r = 0; r < nRanks; r++)
{
NCCLCHECK(ncclRecv(((char*) recvbuff) + r * rankOffset, count, type, r, comm,
stream));
}
}
NCCLCHECK(ncclGroupEnd());
return testSuccess;
}
struct testColl gatherTest = { "Gather", GatherGetCollByteCount, GatherInitData,
GatherGetBw, GatherRunColl };
void
GatherGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
GatherGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
GatherRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &gatherTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
int begin_root, end_root;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if(root != -1)
{
begin_root = end_root = root;
}
else
{
begin_root = 0;
end_root = args->nProcs * args->nThreads * args->nGpus - 1;
}
for(int i = 0; i < type_count; i++)
{
for(int j = begin_root; j <= end_root; j++)
{
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0,
"none", j));
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { GatherGetBuffSize, GatherRunTest };
+6
Voir le fichier
@@ -0,0 +1,6 @@
#ifndef RCCL_TESTS_GIT_VERSION_H_
#define RCCL_TESTS_GIT_VERSION_H_
extern const char* rcclTestsGitHash;
#endif
+144
Voir le fichier
@@ -0,0 +1,144 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
#define ALIGN 4
void
HyperCubeGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
size_t base = (count / nranks) & -(16 / eltSize);
*sendcount = base;
*recvcount = base * nranks;
*sendInplaceOffset = base;
*recvInplaceOffset = 0;
*paramcount = base;
}
testResult_t
HyperCubeInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? ((char*) args->recvbuffs[i]) + rank * args->sendBytes
: args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, ncclSum, 33 * rep + rank, 1, 0));
for(int j = 0; j < nranks; j++)
{
TESTCHECK(InitData((char*) args->expected[i] + args->sendBytes * j, sendcount,
0, type, ncclSum, 33 * rep + j, 1, 0));
}
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
HyperCubeGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize * (nranks - 1)) / 1.0E9 / sec;
*algBw = baseBw;
double factor = 1;
*busBw = baseBw * factor;
}
testResult_t
HyperCubeRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
char* sbuff = (char*) sendbuff;
char* rbuff = (char*) recvbuff;
int nRanks;
NCCLCHECK(ncclCommCount(comm, &nRanks));
int rank;
NCCLCHECK(ncclCommUserRank(comm, &rank));
size_t rankSize = count * wordSize(type);
if(rbuff + rank * rankSize != sbuff)
CUDACHECK(cudaMemcpyAsync(rbuff + rank * rankSize, sbuff, rankSize,
cudaMemcpyDeviceToDevice, stream));
// Hypercube AllGather
for(int mask = 1; mask < nRanks; mask <<= 1)
{
NCCLCHECK(ncclGroupStart());
int s = rank & ~(mask - 1);
int r = s ^ mask;
NCCLCHECK(ncclSend(rbuff + s * rankSize, count * mask, type, rank ^ mask, comm,
stream));
NCCLCHECK(ncclRecv(rbuff + r * rankSize, count * mask, type, rank ^ mask, comm,
stream));
NCCLCHECK(ncclGroupEnd());
}
return testSuccess;
}
struct testColl hyperCubeTest = { "HyperCube", HyperCubeGetCollByteCount,
HyperCubeInitData, HyperCubeGetBw, HyperCubeRunColl };
void
HyperCubeGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
HyperCubeGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
HyperCubeRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &hyperCubeTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
// Check if this is a power of 2
int nRanks = args->nProcs * args->nThreads * args->nGpus;
if(nRanks && !(nRanks & (nRanks - 1)))
{
for(int i = 0; i < type_count; i++)
{
TESTCHECK(
TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0, "", -1));
}
}
else
{
printf("nRanks %d is not a power of 2, skipping\n", nRanks);
}
return testSuccess;
}
struct testEngine ncclTestEngine = { HyperCubeGetBuffSize, HyperCubeRunTest };
+70
Voir le fichier
@@ -0,0 +1,70 @@
/*************************************************************************
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#ifndef NCCL1_COMPAT_H
#define NCCL1_COMPAT_H
#ifndef NCCL_MAJOR // NCCL 1.x
# define NCCL_MAJOR 1
# define NCCL_MINOR 0
# define ncclNumOps nccl_NUM_OPS
# define ncclNumTypes nccl_NUM_TYPES
static ncclResult_t
ncclGroupStart()
{
return ncclSuccess;
}
static ncclResult_t
ncclGroupEnd()
{
return ncclSuccess;
}
# define CHECKCOUNT(count) \
if(count > INT_MAX) return ncclInvalidArgument;
static ncclResult_t
ncclReduce(const void* sendbuff, void* recvbuff, size_t count, ncclDataType_t datatype,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
CHECKCOUNT(count);
return ncclReduce(sendbuff, recvbuff, (int) count, datatype, op, root, comm, stream);
}
static ncclResult_t
ncclAllReduce(const void* sendbuff, void* recvbuff, size_t count, ncclDataType_t datatype,
ncclRedOp_t op, ncclComm_t comm, cudaStream_t stream)
{
CHECKCOUNT(count);
return ncclAllReduce(sendbuff, recvbuff, (int) count, datatype, op, comm, stream);
}
static ncclResult_t
ncclBcast(void* buff, size_t count, ncclDataType_t datatype, int root, ncclComm_t comm,
cudaStream_t stream)
{
CHECKCOUNT(count);
return ncclBcast(buff, (int) count, datatype, root, comm, stream);
}
static ncclResult_t
ncclReduceScatter(const void* sendbuff, void* recvbuff, size_t recvcount,
ncclDataType_t datatype, ncclRedOp_t op, ncclComm_t comm,
cudaStream_t stream)
{
CHECKCOUNT(recvcount);
return ncclReduceScatter(sendbuff, recvbuff, (int) recvcount, datatype, op, comm,
stream);
}
static ncclResult_t
ncclAllGather(const void* sendbuff, void* recvbuff, size_t sendcount,
ncclDataType_t datatype, ncclComm_t comm, cudaStream_t stream)
{
CHECKCOUNT(sendcount);
return ncclAllGather(sendbuff, (int) sendcount, datatype, recvbuff, comm, stream);
}
#endif
#endif
Fichier diff supprimé car celui-ci est trop grand Voir la Diff
+142
Voir le fichier
@@ -0,0 +1,142 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
ReduceGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset, size_t count,
size_t eltSize, int nranks)
{
*sendcount = count;
*recvcount = count;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
*paramcount = *sendcount;
}
testResult_t
ReduceInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, op, rep, nranks, rank));
CUDACHECK(cudaMemcpy(args->expected[i], args->recvbuffs[i], args->expectedBytes,
cudaMemcpyDefault));
if(rank == root)
TESTCHECK(
InitDataReduce(args->expected[i], recvcount, 0, type, op, rep, nranks));
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
ReduceGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize) / 1.0E9 / sec;
*algBw = baseBw;
*busBw = baseBw;
}
testResult_t
ReduceRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
NCCLCHECK(ncclReduce(sendbuff, recvbuff, count, type, op, root, comm, stream));
return testSuccess;
}
struct testColl reduceTest = { "Reduce", ReduceGetCollByteCount, ReduceInitData,
ReduceGetBw, ReduceRunColl };
void
ReduceGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
ReduceGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
ReduceRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &reduceTest;
ncclDataType_t* run_types;
ncclRedOp_t* run_ops;
const char ** run_typenames, **run_opnames;
int type_count, op_count;
int begin_root, end_root;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if((int) op != -1)
{
op_count = 1;
run_ops = &op;
run_opnames = &opName;
}
else
{
op_count = test_opnum;
run_ops = test_ops;
run_opnames = test_opnames;
}
if(root != -1)
{
begin_root = end_root = root;
}
else
{
begin_root = 0;
end_root = args->nProcs * args->nThreads * args->nGpus - 1;
}
for(int i = 0; i < type_count; i++)
{
for(int j = 0; j < op_count; j++)
{
#if defined(RCCL_FLOAT8)
if((run_types[i] == ncclFp8E4M3 || run_types[i] == ncclFp8E5M2) &&
run_ops[j] == ncclProd)
continue;
#endif
for(int k = begin_root; k <= end_root; k++)
{
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], run_ops[j],
run_opnames[j], k));
}
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { ReduceGetBuffSize, ReduceRunTest };
+131
Voir le fichier
@@ -0,0 +1,131 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
ReduceScatterGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
size_t base = (count / nranks) & -(16 / eltSize);
*sendcount = base * nranks;
*recvcount = base;
*sendInplaceOffset = 0;
*recvInplaceOffset = base;
*paramcount = base;
}
testResult_t
ReduceScatterInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op,
int root, int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, 0, type, op, rep, nranks, rank));
CUDACHECK(cudaMemcpy(args->expected[i], args->recvbuffs[i], args->expectedBytes,
cudaMemcpyDefault));
TESTCHECK(InitDataReduce(args->expected[i], recvcount, rank * recvcount, type, op,
rep, nranks));
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
ReduceScatterGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize * nranks) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (nranks - 1)) / ((double) nranks);
*busBw = baseBw * factor;
}
testResult_t
ReduceScatterRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
NCCLCHECK(ncclReduceScatter(sendbuff, recvbuff, count, type, op, comm, stream));
return testSuccess;
}
struct testColl reduceScatterTest = { "ReduceScatter", ReduceScatterGetCollByteCount,
ReduceScatterInitData, ReduceScatterGetBw,
ReduceScatterRunColl };
void
ReduceScatterGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
ReduceScatterGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
ReduceScatterRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &reduceScatterTest;
ncclDataType_t* run_types;
ncclRedOp_t* run_ops;
const char ** run_typenames, **run_opnames;
int type_count, op_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if((int) op != -1)
{
run_ops = &op;
run_opnames = &opName;
op_count = 1;
}
else
{
op_count = test_opnum;
run_ops = test_ops;
run_opnames = test_opnames;
}
for(int i = 0; i < type_count; i++)
{
for(int j = 0; j < op_count; j++)
{
#if defined(RCCL_FLOAT8)
if((run_types[i] == ncclFp8E4M3 || run_types[i] == ncclFp8E5M2) &&
run_ops[j] == ncclProd)
continue;
#endif
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], run_ops[j],
run_opnames[j], -1));
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { ReduceScatterGetBuffSize, ReduceScatterRunTest };
+137
Voir le fichier
@@ -0,0 +1,137 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
ScatterGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
*recvcount = (count / nranks) & -(16 / eltSize);
*sendcount = (*recvcount) * nranks;
*sendInplaceOffset = 0;
*recvInplaceOffset = *recvcount;
*paramcount = *recvcount;
}
testResult_t
ScatterInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
if(rank == root)
TESTCHECK(InitData(data, sendcount, 0, type, ncclSum, rep, 1, 0));
TESTCHECK(InitData(args->expected[i], recvcount, rank * recvcount, type, ncclSum,
rep, 1, 0));
CUDACHECK(cudaDeviceSynchronize());
}
return testSuccess;
}
void
ScatterGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * nranks * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = ((double) (nranks - 1)) / ((double) (nranks));
*busBw = baseBw * factor;
}
testResult_t
ScatterRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
int nRanks;
NCCLCHECK(ncclCommCount(comm, &nRanks));
int rank;
NCCLCHECK(ncclCommUserRank(comm, &rank));
size_t rankOffset = count * wordSize(type);
if(count == 0) return testSuccess;
NCCLCHECK(ncclGroupStart());
if(rank == root)
{
for(int r = 0; r < nRanks; r++)
{
NCCLCHECK(ncclSend(((char*) sendbuff) + r * rankOffset, count, type, r, comm,
stream));
}
}
NCCLCHECK(ncclRecv(recvbuff, count, type, root, comm, stream));
NCCLCHECK(ncclGroupEnd());
return testSuccess;
}
struct testColl scatterTest = { "Scatter", ScatterGetCollByteCount, ScatterInitData,
ScatterGetBw, ScatterRunColl };
void
ScatterGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
ScatterGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
ScatterRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &scatterTest;
ncclDataType_t* run_types;
const char** run_typenames;
int type_count;
int begin_root, end_root;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if(root != -1)
{
begin_root = end_root = root;
}
else
{
begin_root = 0;
end_root = args->nProcs * args->nThreads * args->nGpus - 1;
}
for(int i = 0; i < type_count; i++)
{
for(int j = begin_root; j <= end_root; j++)
{
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], (ncclRedOp_t) 0,
"none", j));
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { ScatterGetBuffSize, ScatterRunTest };
+135
Voir le fichier
@@ -0,0 +1,135 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#include "common.h"
#include "cuda_runtime.h"
void
SendRecvGetCollByteCount(size_t* sendcount, size_t* recvcount, size_t* paramcount,
size_t* sendInplaceOffset, size_t* recvInplaceOffset,
size_t count, size_t eltSize, int nranks)
{
*sendcount = count;
*recvcount = count;
*sendInplaceOffset = 0;
*recvInplaceOffset = 0;
*paramcount = *sendcount;
}
testResult_t
SendRecvInitData(struct threadArgs* args, ncclDataType_t type, ncclRedOp_t op, int root,
int rep, int in_place)
{
size_t sendcount = args->sendBytes / wordSize(type);
size_t recvcount = args->expectedBytes / wordSize(type);
int nranks = args->nProcs * args->nThreads * args->nGpus;
for(int i = 0; i < args->nGpus; i++)
{
CUDACHECK(cudaSetDevice(args->gpus[i]));
int rank = ((args->proc * args->nThreads + args->thread) * args->nGpus + i);
CUDACHECK(cudaMemset(args->recvbuffs[i], 0, args->expectedBytes));
void* data = in_place ? args->recvbuffs[i] : args->sendbuffs[i];
TESTCHECK(InitData(data, sendcount, rank * sendcount, type, ncclSum, rep, 1, 0));
int peer = (rank - 1 + nranks) % nranks;
TESTCHECK(InitData(args->expected[i], recvcount, peer * recvcount, type, ncclSum,
rep, 1, 0));
CUDACHECK(cudaDeviceSynchronize());
}
// We don't support in-place sendrecv
args->reportErrors = in_place ? 0 : 1;
return testSuccess;
}
void
SendRecvGetBw(size_t count, int typesize, double sec, double* algBw, double* busBw,
int nranks)
{
double baseBw = (double) (count * typesize) / 1.0E9 / sec;
*algBw = baseBw;
double factor = 1;
*busBw = baseBw * factor;
}
testResult_t
SendRecvRunColl(void* sendbuff, void* recvbuff, size_t count, ncclDataType_t type,
ncclRedOp_t op, int root, ncclComm_t comm, cudaStream_t stream)
{
int nRanks;
NCCLCHECK(ncclCommCount(comm, &nRanks));
int rank;
NCCLCHECK(ncclCommUserRank(comm, &rank));
int recvPeer = (rank - 1 + nRanks) % nRanks;
int sendPeer = (rank + 1) % nRanks;
NCCLCHECK(ncclGroupStart());
NCCLCHECK(ncclSend(sendbuff, count, type, sendPeer, comm, stream));
NCCLCHECK(ncclRecv(recvbuff, count, type, recvPeer, comm, stream));
NCCLCHECK(ncclGroupEnd());
return testSuccess;
}
struct testColl sendRecvTest = { "SendRecv", SendRecvGetCollByteCount, SendRecvInitData,
SendRecvGetBw, SendRecvRunColl };
void
SendRecvGetBuffSize(size_t* sendcount, size_t* recvcount, size_t count, int nranks)
{
size_t paramcount, sendInplaceOffset, recvInplaceOffset;
SendRecvGetCollByteCount(sendcount, recvcount, &paramcount, &sendInplaceOffset,
&recvInplaceOffset, count, /*eltSize=*/1, nranks);
}
testResult_t
SendRecvRunTest(struct threadArgs* args, int root, ncclDataType_t type,
const char* typeName, ncclRedOp_t op, const char* opName)
{
args->collTest = &sendRecvTest;
ncclDataType_t* run_types;
ncclRedOp_t* run_ops;
const char ** run_typenames, **run_opnames;
int type_count, op_count;
if((int) type != -1)
{
type_count = 1;
run_types = &type;
run_typenames = &typeName;
}
else
{
type_count = test_typenum;
run_types = test_types;
run_typenames = test_typenames;
}
if((int) op != -1)
{
op_count = 1;
run_ops = &op;
run_opnames = &opName;
}
else
{
op_count = test_opnum;
run_ops = test_ops;
run_opnames = test_opnames;
}
for(int i = 0; i < type_count; i++)
{
for(int j = 0; j < op_count; j++)
{
TESTCHECK(TimeTest(args, run_types[i], run_typenames[i], run_ops[j],
run_opnames[j], -1));
}
}
return testSuccess;
}
struct testEngine ncclTestEngine = { SendRecvGetBuffSize, SendRecvRunTest };
+35
Voir le fichier
@@ -0,0 +1,35 @@
#include "timer.h"
// Make sure to compile this translation unit with the host compiler and not
// nvcc, lest you hit an internal compiler error (ICE) with GCC 10.3.0
#include <chrono>
namespace
{
std::uint64_t
now()
{
using clock = std::chrono::steady_clock;
return std::chrono::duration_cast<std::chrono::nanoseconds>(
clock::now().time_since_epoch())
.count();
}
} // namespace
timer::timer() { t0 = now(); }
double
timer::elapsed() const
{
std::uint64_t t1 = now();
return 1.e-9 * (t1 - t0);
}
double
timer::reset()
{
std::uint64_t t1 = now();
double ans = 1.e-9 * (t1 - t0);
t0 = t1;
return ans;
}
+17
Voir le fichier
@@ -0,0 +1,17 @@
#ifndef _408319ecdd5b47b28bf8f511c4fdf816
#define _408319ecdd5b47b28bf8f511c4fdf816
#include <cstdint>
// Can't include <chrono> because of bug with gcc 10.3.0
class timer
{
std::uint64_t t0;
public:
timer();
double elapsed() const;
double reset();
};
#endif
+74
Voir le fichier
@@ -0,0 +1,74 @@
#
# Copyright (c) 2015-2022, NVIDIA CORPORATION. All rights reserved.
# Modifications are Copyright (c) 2019-2025 Advanced Micro Devices, Inc. All rights reserved.
#
# See LICENSE.txt for license information
#
#include ../../makefiles/common.mk
.PHONY: all clean
BUILDDIR := $(abspath ../../build)
DST_DIR := $(BUILDDIR)/test/verifiable
ROCM_PATH ?= /opt/rocm
MPI_HOME ?= /usr/lib/x86_64-linux-gnu
PREFIX ?= /usr/local
VERBOSE ?= 0
DEBUG ?= 0
NCCL_HOME ?= ""
HIPCC = $(ROCM_PATH)/bin/amdclang++
CXX = $(HIPCC)
HIPCUFLAGS := -std=c++14
LDFLAGS :=
HIPLDFLAGS :=
ifneq ($(NCCL_HOME), "")
HIPCUFLAGS += -I$(NCCL_HOME)/ -I$(NCCL_HOME)/include
HIPLDFLAGS += -Wl,-rpath,$(NCCL_HOME) -L$(NCCL_HOME) -L$(NCCL_HOME)/lib
endif
HIPCUFLAGS += -I$(ROCM_PATH)/include
HIPCUFLAGS += -I$(ROCM_PATH)/include/hip
LDFLAGS += -L$(ROCM_PATH)/lib -lhsa-runtime64 -lrt
HIPLDFLAGS += $(CUSTOM_RCCL_LIB) -L$(ROCM_PATH)/lib -lhsa-runtime64 -lamdhip64 -lstdc++ -lrt
ifeq ($(DEBUG), 0)
HIPCUFLAGS += -O3
else
HIPCUFLAGS += -O0 -g -ggdb3
endif
ifeq ($(VERBOSE), 0)
.SILENT:
endif
ifeq ($(MPI), 1)
HIPCUFLAGS += -DMPI_SUPPORT -I${MPI_HOME}/include -I${MPI_HOME}/include/openmpi -I${MPI_HOME}/openmpi/include -I${MPI_HOME}/openmpi/include/openmpi
HIPLDFLAGS += -L${MPI_HOME}/lib -L${MPI_HOME}/openmpi/lib -lmpi
else ifeq ($(MPICH), 1)
HIPCUFLAGS += -DMPI_SUPPORT -I${MPI_HOME}/include -I${MPI_HOME}/mpich/include -I/usr/include/x86_64-linux-gnu/mpich
HIPLDFLAGS += -L${MPI_HOME}/lib -L${MPI_HOME}/mpich/lib -lmpich
endif
LIBRARIES += rccl
HIPLDFLAGS += $(LIBRARIES:%=-l%)
all: $(DST_DIR)/verifiable.o $(DST_DIR)/self_test
clean:
rm -rf $(DST_DIR)
TEST_VERIFIABLE_SRCDIR := .
TEST_VERIFIABLE_BUILDDIR := $(DST_DIR)
include verifiable.mk
self_test: $(DST_DIR)/self_test
$(DST_DIR)/self_test: verifiable.cpp verifiable.h
@printf "Linking %s\n" $@
@mkdir -p $(DST_DIR)
$(HIPCC) -o $@ $(HIPCUFLAGS) -DSELF_TEST=1 verifiable.cpp $(HIPLDFLAGS)
@@ -0,0 +1,236 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
/* Generate parameters for our error bound model of floating point average
* (sum of scaled values) by sampling sums of random sequences for each
* floating point type.
*
* The model has parameters "coef" and "power", where for two floats a & b,
* they are close enough if and only if:
* abs(intBits(a) - intBits(b)) <= 1 + coef*pow(rank_n, power);
*
* Where intBits(x) is the reinterpretation of the float bitpattern as an integer.
*
* Compile with:
* nvcc -gencode=arch=compute_80,code=sm_80
*/
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <cuda_fp16.h>
#include <hip/hip_bfloat16.h>
using std::uint32_t;
using std::uint64_t;
using bfloat16 = hip_bfloat16;
template <typename T>
struct float_traits;
template <>
struct float_traits<float>
{
static constexpr int mantissa_bits = 23;
static constexpr int exponent_bits = 8;
using uint_t = uint32_t;
__device__ static float make(double x) { return (float) x; }
__device__ static float make(uint64_t x) { return (float) x; }
__device__ static double todouble(float x) { return x; }
__device__ static float add(float a, float b) { return a + b; }
__device__ static float mul(float a, float b) { return a * b; }
};
template <>
struct float_traits<double>
{
static constexpr int mantissa_bits = 52;
static constexpr int exponent_bits = 11;
using uint_t = uint64_t;
__device__ static double make(double x) { return x; }
__device__ static double make(uint64_t x) { return (double) x; }
__device__ static double todouble(double x) { return x; }
__device__ static double add(double a, double b) { return a + b; }
__device__ static double mul(double a, double b) { return a * b; }
};
template <>
struct float_traits<__half>
{
static constexpr int mantissa_bits = 10;
static constexpr int exponent_bits = 5;
using uint_t = uint16_t;
__device__ static __half make(double x) { return __float2half((float) x); }
__device__ static __half make(uint64_t x) { return __int2half_rn(x); }
__device__ static double todouble(__half x) { return __half2float(x); }
__device__ static __half add(__half a, __half b) { return __hadd(a, b); }
__device__ static __half mul(__half a, __half b) { return __hmul(a, b); }
};
template <>
struct float_traits<bfloat16>
{
static constexpr int mantissa_bits = 7;
static constexpr int exponent_bits = 8;
using uint_t = uint16_t;
__device__ static bfloat16 make(double x) { return bfloat16(x); }
__device__ static bfloat16 make(uint64_t x) { return bfloat16(x); }
__device__ static double todouble(bfloat16 x) { return double(x); }
__device__ static bfloat16 add(bfloat16 a, bfloat16 b)
{
return bfloat16(__hadd((float) a, (float) b));
}
__device__ static bfloat16 mul(bfloat16 a, bfloat16 b)
{
return bfloat16(__hmul((float) a, (float) b));
}
};
template <typename F>
__device__ int
compare(F a, F b)
{
union
{
typename float_traits<F>::uint_t ua;
F fa;
};
union
{
typename float_traits<F>::uint_t ub;
F fb;
};
ua = 0;
ub = 0;
fa = a;
fb = b;
// std::printf("bits(%1.10f)=%x bits(%1.10f)=%x\n", fa, ua, fb, ub);
return ua < ub ? ub - ua : ua - ub;
}
struct xoshiro256ss
{
uint64_t s[4];
__device__ xoshiro256ss(int seed)
{
constexpr uint64_t src[4] = { 0xbb99e851d1f545cc, 0xbfc4022389ca40cb,
0xe84aff5cb1914af5, 0x845999858284de77 };
for(int i = 0; i < 4; i++)
s[i] = src[i] + (seed + i) * 0xb45de8a52fdb65d3;
}
__device__ uint64_t operator()()
{
auto rol64 = [](uint64_t x, int k) { return (x << k) | (x >> (64 - k)); };
uint64_t const result = rol64(s[1] * 5, 7) * 9;
uint64_t const t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rol64(s[3], 45);
return result;
}
};
static __device__ int
__reduce_max_sync(unsigned int mask, int value)
{
// We ignore mask, since all bits are set when calling them in the
// test code below.
int width = warpSize;
for(unsigned int i = warpSize; i; i >>= 1)
{
value = max(__shfl_down(value, i, width), value);
}
return value;
}
template <typename F>
__global__ void
kernel()
{
using traits = float_traits<F>;
constexpr int samps = 4 << 10;
__shared__ F accf[samps];
__shared__ double accd[samps];
xoshiro256ss rng(threadIdx.x);
float expo_avg = 1;
for(int pass = 0; pass < 2; pass++)
{
F scalar = traits::make(1.0 / (3.14159 + .5 * threadIdx.x));
int err_max = 0;
float coef = 0;
double expo_sum = 0;
int expo_n = 0;
int max_ranks =
std::is_same<F, float>::value ? 16 << 10 : 1 << traits::mantissa_bits;
for(int round = 0; round < 1 + (16 << 10) / max_ranks; round++)
{
// for(int round=0; round < 2; round++) {
for(int i = threadIdx.x; i < samps; i += blockDim.x)
{
accf[i] = (F) 0;
accd[i] = 0;
}
__syncthreads();
for(int r = 0; r < max_ranks; r++)
{
int err = 0;
for(int i = threadIdx.x; i < samps; i += blockDim.x)
{
constexpr uint64_t m = (1ll << traits::mantissa_bits) - 1;
double d = std::is_same<F, float>::value ? double(rng() & m) : 1.0;
F f = traits::make(d);
accf[i] = traits::add(accf[i], traits::mul(scalar, f));
accd[i] += traits::todouble(f);
// if(threadIdx.x==0 && std::is_same<F,half>::value) std::printf("
// r=%d f=%f\n", r, traits::todouble(accf[i]));
int e = compare(accf[i], traits::mul(scalar, traits::make(accd[i])));
err = err > e ? err : e;
}
err = __reduce_max_sync(-1u, err);
err_max = err_max > err ? err_max : err;
if(r >= 2)
{
// err = 1 + coef*pow(r,expo)
float c = float(err - 1) / powf(float(r), expo_avg);
coef = coef > c ? coef : c;
}
if(r >= 2)
{
double expo = log2f(1 + err_max) / log2f(r);
expo_sum += expo;
expo_n++;
// if(threadIdx.x==0 && std::is_same<F,half>::value) std::printf("
// r=%d err=%d errmax=%d expo=%f sum=%f n=%d\n", r, err, err_max,
// expo, expo_sum, expo_n);
}
}
}
if(pass == 0)
expo_avg = expo_sum / expo_n;
else if(threadIdx.x == 0)
printf(" coef=%1.10f expo=%1.10f\n", coef, expo_avg);
}
}
int
main()
{
std::printf("type=float:\n");
kernel<float><<<1, 32>>>();
cudaDeviceSynchronize();
std::printf("\ntype=half:\n");
kernel<half><<<1, 32>>>();
cudaDeviceSynchronize();
std::printf("\ntype=bfloat16:\n");
kernel<bfloat16><<<1, 32>>>();
cudaDeviceSynchronize();
return 0;
}
Fichier diff supprimé car celui-ci est trop grand Voir la Diff
+67
Voir le fichier
@@ -0,0 +1,67 @@
/*************************************************************************
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
* Modifications Copyright (c) 2020-2022 Advanced Micro Devices, Inc. All rights reserved.
*
* See LICENSE.txt for license information
************************************************************************/
#ifndef _d41d8cd98f00b204e9800998ecf8427e
#define _d41d8cd98f00b204e9800998ecf8427e
#include <cuda_runtime.h>
#include <stdint.h>
/* Routines for launching kernels that verify reduction results. A significant
* feature of these routines is they carefully craft floating point input
* to produce exactly predictable output.
*
* int elt_ty: actually just a ncclDataType_t
*
* int red_op: mostly just a ncclRedOp_t. Since PreMulSum ops are dynamically
* created, these are encoded as the value ncclNumOps and their scalar is
* assumed to be `ncclVerifiablePremulScalar(rank_me)`
*
* uint64_t seed: arbitrary 64-bits to use in seeding the random values
*
* intptr_t elt_ix0: index of first element pointed to by elts when generating
* random values. This makes it possible to generate subsequences independently
* as well as in aggregate.
*
* int rank_n: Number of contributions into the reduction. Non-reduction
* collectives like broadcast, gather, etc will always set this to one.
*
* int rank_me: Index of this contribution
*/
// Use this as the local scalar for PreMulSum ops
template <typename T>
__host__ __device__ T
ncclVerifiablePremulScalar(int rank_me)
{
return T(rank_me % 2 == 0 ? 1.0f : 2.0f);
}
// Enqueue kernel to generate data which is to be reduced.
void
ncclVerifiablePrepareInput(void* elts, intptr_t elt_n, int elt_ty, int red_op, int rank_n,
int rank_me, uint64_t seed, intptr_t elt_ix0,
cudaStream_t stream);
// Enqueue kernel to generate expected results of reduction.
void
ncclVerifiablePrepareExpected(void* elts, intptr_t elt_n, int elt_ty, int red_op,
int rank_n, uint64_t seed, intptr_t elt_ix0,
cudaStream_t stream);
// Enqueue kernel to verify reduced data matches expectation. The number of
// failed elements is written to bad_elt_n which must be in cudaHost memory.
// If `expected == nullptr` then the expected results are generated on-the-fly
// which can be costly. Thus if you plan to run the same reduction multiple
// times it is advantageous to precompute the expected values with
// ncclVerifiablePrepareExpected and pass them as `expected` here.
void
ncclVerifiableVerify(void const* results, void const* expected, intptr_t elt_n,
int elt_ty, int red_op, int rank_n, uint64_t seed, intptr_t elt_ix0,
int64_t* bad_elt_n, cudaStream_t stream);
#endif
@@ -0,0 +1,33 @@
# Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
# Modifications Copyright (c) 2020-2024 Advanced Micro Devices, Inc. All rights reserved.
#
# See LICENSE.txt for license information
# We requires both of the following paths to be set upon including this makefile
# TEST_VERIFIABLE_SRCDIR = <points to this directory>
# TEST_VERIFIABLE_BUILDDIR = <points to destination of .o file>
TEST_VERIFIABLE_HDRS = $(TEST_VERIFIABLE_SRCDIR)/verifiable.h
TEST_VERIFIABLE_OBJS = $(TEST_VERIFIABLE_BUILDDIR)/verifiable.o
${HIPIFY_DIR}/verifiable.cpp: $(TEST_VERIFIABLE_SRCDIR)/verifiable.cpp
@printf "Hipifying %-35s > %s\n" $< $@
@mkdir -p ${HIPIFY_DIR}
hipify-perl -quiet-warnings $< > $@
${HIPIFY_DIR}/verifiable.h: $(TEST_VERIFIABLE_SRCDIR)/verifiable.h
@printf "Hipifying %-35s > %s\n" $< $@
@mkdir -p ${HIPIFY_DIR}
hipify-perl -quiet-warnings $< > $@
${HIPIFY_DIR}/rccl_float8.h: $(TEST_VERIFIABLE_SRCDIR)/../src/rccl_float8.h
@printf "Hipifying %-35s > %s\n" $< $@
@mkdir -p ${HIPIFY_DIR}
hipify-perl -quiet-warnings $< > $@
$(TEST_VERIFIABLE_BUILDDIR)/verifiable.o: $(HIPIFY_DIR)/verifiable.cpp $(HIPIFY_DIR)/verifiable.h $(HIPIFY_DIR)/rccl_float8.h
@printf "Compiling %s\n" $@
@mkdir -p $(TEST_VERIFIABLE_BUILDDIR)
echo " $(HIPCC) -o $@ $(HIPCUFLAGS) -c $<"
$(HIPCC) -o $@ $(HIPCUFLAGS) -c $<