Files
rocm-systems/src/device/sendrecv.h
T

93 lines
4.0 KiB
C++
Raw Normal View History

2020-05-12 14:40:18 -07:00
/*************************************************************************
2022-01-07 06:39:55 -08:00
* Copyright (c) 2015-2022, NVIDIA CORPORATION. All rights reserved.
2020-05-12 14:40:18 -07:00
*
* See LICENSE.txt for license information
************************************************************************/
2023-09-26 05:47:28 -07:00
#include "device.h"
2020-05-12 14:40:18 -07:00
#include "collectives.h"
2021-07-08 14:12:04 -07:00
#include "primitives.h"
2020-05-12 14:40:18 -07:00
2021-07-08 14:12:04 -07:00
template<typename T, typename RedOp>
struct RunWork<ncclFuncSendRecv, T, RedOp, NCCL_ALGO_RING, NCCL_PROTO_SIMPLE> {
2022-08-18 02:53:17 -07:00
template<typename Proto>
2023-04-03 05:32:07 -07:00
__device__ void runSend(const int tid, const int nthreads, const uint8_t group, struct ncclWorkElemP2p* args) {
2022-05-24 02:02:31 -07:00
void* buff = reinterpret_cast<void*>(uintptr_t(args->buffHi32)<<32 | args->buffLo32);
2023-02-27 02:48:21 -08:00
ssize_t count = reinterpret_cast<size_t>(size_t(args->countHi32)<<32 | args->countLo32);
2022-01-07 06:39:55 -08:00
if (args->peer == ncclShmem.comm.rank) {
struct ncclWorkElemP2p* recvArgs = args-1;
2022-05-24 02:02:31 -07:00
void* recvBuff = reinterpret_cast<void*>(uintptr_t(recvArgs->buffHi32)<<32 | recvArgs->buffLo32);
if (buff != recvBuff) {
2023-04-03 05:32:07 -07:00
reduceCopy<COLL_UNROLL, RedOp, T, 0,1,1, 0,1,1, /*PreOpSrcs=*/0>
2023-02-27 02:48:21 -08:00
(tid, nthreads, 0, nullptr, false, 1, &buff, 1, &recvBuff, count);
2022-01-07 06:39:55 -08:00
}
} else {
2022-08-18 02:53:17 -07:00
int chunkSize = args->chunkSize/sizeof(T);
if (args->proto == NCCL_PROTO_LL) chunkSize /= 2;
2022-01-07 06:39:55 -08:00
int const peer = args->peer;
Primitives<T, RedOp, FanAsymmetric<0, 1>, 1, Proto, 1> prims
2023-09-26 05:47:28 -07:00
(tid, nthreads, nullptr, &peer, buff, nullptr, /*redOpArg(ignored)=*/0, group, 1, 1, nullptr, ncclShmem.comm.p2pChunkSize/sizeof(T));
2022-05-24 02:02:31 -07:00
size_t offset = 0;
2022-01-07 06:39:55 -08:00
do {
2022-05-24 02:02:31 -07:00
int nelem = min(size_t(chunkSize), count-offset);
2022-01-07 06:39:55 -08:00
prims.directSend(offset, offset, nelem);
offset += nelem;
} while(offset < count);
}
}
2020-05-12 14:40:18 -07:00
2022-08-18 02:53:17 -07:00
template<typename Proto>
2023-04-03 05:32:07 -07:00
__device__ void runRecv(const int tid, const int nthreads, const uint8_t group, struct ncclWorkElemP2p* args) {
2022-01-07 06:39:55 -08:00
if (args->peer != ncclShmem.comm.rank) {
2022-05-24 02:02:31 -07:00
void* buff = reinterpret_cast<void*>(uintptr_t(args->buffHi32)<<32 | args->buffLo32);
ssize_t count = reinterpret_cast<size_t>(size_t(args->countHi32)<<32 | args->countLo32);
2022-08-18 02:53:17 -07:00
int chunkSize = args->chunkSize/sizeof(T);
if (args->proto == NCCL_PROTO_LL) chunkSize /= 2; // This is to account for chunkEffectiveSize
2022-01-07 06:39:55 -08:00
int const peer = args->peer;
Primitives<T, RedOp, FanAsymmetric<1, 0>, 1, Proto, 1> prims
2023-09-26 05:47:28 -07:00
(tid, nthreads, &peer, nullptr, nullptr, buff, /*redOpArg(ignored)=*/0, group, 1, 1, nullptr, ncclShmem.comm.p2pChunkSize/sizeof(T));
2022-05-24 02:02:31 -07:00
size_t offset = 0;
2022-01-07 06:39:55 -08:00
do {
2022-05-24 02:02:31 -07:00
int nelem = min(size_t(chunkSize), count-offset);
2022-01-07 06:39:55 -08:00
prims.directRecv(offset, nelem);
offset += nelem;
} while(offset < count);
}
}
2020-05-12 14:40:18 -07:00
2022-01-07 06:39:55 -08:00
__device__ __forceinline__ void run(ncclWork *work) {
struct ncclWorkElemP2p* args = work->p2pElems;
int ngroups = args->ngroups;
int tid = threadIdx.x;
int wid = tid / WARP_SIZE;
// This has to work even for groups of 2.5 warps (which is 8 groups, and means 3
// warps for send, 2 warps for recv).
// warpStarts were rounded thanks to int division, but for group number we need to round the other way around
// So we mirror wid then mirror again the group.
#define NWARPS (NCCL_MAX_NTHREADS/WARP_SIZE)
2023-04-03 05:32:07 -07:00
uint8_t group = ngroups-1- (NWARPS-1-wid) * ngroups / NWARPS;
2022-01-07 06:39:55 -08:00
args += group;
tid -= args->warpStart * WARP_SIZE;
int nthreads = args->nWarps * WARP_SIZE;
2022-05-24 02:02:31 -07:00
if (args->p2pType == ncclWorkP2pTypeUnused) return;
2022-01-07 06:39:55 -08:00
if (tid >= nthreads || args->peer == -1) return;
2022-08-18 02:53:17 -07:00
// Select Proto here
// This is to allow the same kernel to run multiple primitives on different warps (thread groups)
2022-01-07 06:39:55 -08:00
if ((group%2) == 0) {
2022-08-18 02:53:17 -07:00
if (args->proto == NCCL_PROTO_LL) {
runRecv<ProtoLL>(tid, nthreads, group, args);
} else {
runRecv<ProtoSimple<1,1>>(tid, nthreads, group, args);
}
2022-01-07 06:39:55 -08:00
} else {
2022-08-18 02:53:17 -07:00
if (args->proto == NCCL_PROTO_LL) {
runSend<ProtoLL>(tid, nthreads, group, args);
} else {
runSend<ProtoSimple<1,1>>(tid, nthreads, group, args);
}
2020-05-12 14:40:18 -07:00
}
2021-07-08 14:12:04 -07:00
}
2020-09-04 14:35:05 -07:00
};