2.24.3-1
Network user buffer support for collectives
* Leverage user buffer registration to achieve zero-copy
inter-node communications for Ring, NVLS and Collnet
Add RAS subsystem
* Create a RAS thread keeping track of all NCCL communicators.
* Add a ncclras tool contacting the RAS thread and getting a
report.
Add fp8 support
* Add support for e5m2 and e4m3 8-bit floating point operations.
* Use Tree/PAT algorithms when possible for better numerical
stability.
Add NIC fusion
* Add a NET API to ask the network plugin to fuse a set of
interfaces together.
* Fuse multiple NICs under the same PCI switch as a single,
larger NIC.
Socket connection failure retry
* Retry in case of socket connection failure (unreachable host)
* Avoid "Software caused connection abort" errors on retries
QP connection failure retry
* Retry in case of IB QP connection failure during ibv_modify_qp.
NET API improvements
* Allow plugins to force a flush in case data and completion
ordering is not guaranteed.
* Indicate when completion is not needed (e.g. for the LL128
protocol), allowing plugins to skip generating a completion.
* Allow for full offload of allgather operations when using one
GPU per node.
NCCL_ALGO/NCCL_PROTO strict enforcement
* Extend NCCL_ALGO/NCCL_PROTO syntax to be able to specify
ALGO/PROTO filters for each collective operation.
* Strictly enforce the ALGO/PROTO filters, no longer fall back
on the ring algorithm when the filtering leaves no option and
error out instead.
Enable CUMEM host allocations
* Use cumem functions for host memory allocation by default.
Improved profiler plugin API
* Avoid dependencies with NCCL includes.
* Add information on whether the buffer is registered or not
Adjust PAT tuning
* Improve transition between PAT and ring at scale.
Fix hangs when running with different CPU architectures
* Detect when we use a mix of GPU architectures
* Ensure Algo/Proto decisions are made based on that unified
state.
Fix FD leak in UDS
* Fix a leak when mapping buffers intra-node with cumem IPCs.
Fix crash when mixing buffer registration and graph buffer registration.
* Separate local and graph registration to avoid crashes when we free
buffers.
Fix user buffer registration with dmabuf
* Make ncclSend/ncclRecv communication with buffer registration functional
on network plugins relying on dmabuf for buffer registration.
Fix crash in IB code caused by uninitialized fields.
Fix non-blocking ncclSend/ncclRecv
* Fix case where ncclSend/ncclRecv would return ncclSuccess in non-blocking
mode even though the operation was not enqueued onto the stream.
* Issue #1495
Various compiler tweaks and fixes
* PR #758
Fix typo in ncclTopoPrintGraph
* Issue #1468
[ROCm/rccl commit: 6aae379278]
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
|
||||
#define MAX_CHANNELS 32
|
||||
#define MAX_STEPS 16
|
||||
#define MAX_OPS 16 // Up to 64K ranks for PAT
|
||||
|
||||
#define PROXY_OP_SEND_STATE_OFFSET (ncclProfilerProxyOpSendPosted)
|
||||
#define PROXY_OP_RECV_STATE_OFFSET (ncclProfilerProxyOpRecvPosted)
|
||||
@@ -86,7 +87,7 @@ struct taskEventBase {
|
||||
int rank; // rank of the operation in NCCL communicator
|
||||
const char* name; // FIXME: unused
|
||||
uint64_t commHash; // communicator identifier
|
||||
uint8_t func; // ncclFunc*
|
||||
const char* func; // ncclFunc*
|
||||
int refCount; // number of references for this operation
|
||||
struct group* parent; // parent event group
|
||||
struct taskEventBase* next; // next top level event in group
|
||||
@@ -102,16 +103,14 @@ struct collective {
|
||||
size_t count;
|
||||
size_t trafficBytes;
|
||||
int root;
|
||||
uint8_t datatype;
|
||||
const char* datatype;
|
||||
uint8_t nMaxChannels;
|
||||
uint8_t algo;
|
||||
uint8_t proto;
|
||||
int op;
|
||||
const char* algo;
|
||||
const char* proto;
|
||||
int nWarps;
|
||||
int isCollnet;
|
||||
int isNvls;
|
||||
struct proxyOp send[MAX_CHANNELS];// array of send proxy operation events
|
||||
struct proxyOp recv[MAX_CHANNELS];// array of recv proxy operation events
|
||||
struct proxyOp send[MAX_CHANNELS][MAX_OPS];// array of send proxy operation events
|
||||
struct proxyOp recv[MAX_CHANNELS][MAX_OPS];// array of recv proxy operation events
|
||||
int nProxyOps[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct p2p {
|
||||
@@ -119,9 +118,9 @@ struct p2p {
|
||||
uint8_t func;
|
||||
void const* buff;
|
||||
size_t count;
|
||||
uint8_t datatype;
|
||||
const char* datatype;
|
||||
int peer;
|
||||
struct proxyOp op;
|
||||
struct proxyOp op[MAX_CHANNELS];
|
||||
};
|
||||
|
||||
struct group {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "common.h"
|
||||
#include "err.h"
|
||||
|
||||
#include "profiler_v2.h"
|
||||
#include "profiler_v1.h"
|
||||
|
||||
#endif // end include guard
|
||||
|
||||
@@ -9,16 +9,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
ncclProfileGroup = (1 << 0), // group event type
|
||||
ncclProfileColl = (1 << 1), // host collective call event type
|
||||
ncclProfileP2p = (1 << 2), // host point-to-point call event type
|
||||
ncclProfileProxyOp = (1 << 3), // proxy operation event type
|
||||
ncclProfileProxyStep = (1 << 4), // proxy step event type
|
||||
ncclProfileProxyCtrl = (1 << 5), // proxy control event type
|
||||
ncclProfileNumEvents = ( 6),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t type; // event type descriptor: ncclProfileColl, ...
|
||||
void* parentObj; // pointer to the profiler parent object (for coll is the group)
|
||||
@@ -69,42 +59,8 @@ typedef struct {
|
||||
};
|
||||
} ncclProfilerEventDescr_v1_t;
|
||||
|
||||
typedef enum {
|
||||
ncclProfilerProxyOpSendPosted,
|
||||
ncclProfilerProxyOpSendRemFifoWait,
|
||||
ncclProfilerProxyOpSendTransmitted,
|
||||
ncclProfilerProxyOpSendDone,
|
||||
ncclProfilerProxyOpRecvPosted,
|
||||
ncclProfilerProxyOpRecvReceived,
|
||||
ncclProfilerProxyOpRecvTransmitted,
|
||||
ncclProfilerProxyOpRecvDone,
|
||||
|
||||
/* Legacy proxy profiler states */
|
||||
ncclProfilerProxyStepSendGPUWait,
|
||||
ncclProfilerProxyStepSendWait,
|
||||
ncclProfilerProxyStepRecvWait,
|
||||
ncclProfilerProxyStepRecvFlushWait,
|
||||
ncclProfilerProxyStepRecvGPUWait,
|
||||
|
||||
/* Legacy proxy control states */
|
||||
ncclProfilerProxyCtrlIdle,
|
||||
ncclProfilerProxyCtrlActive,
|
||||
ncclProfilerProxyCtrlSleep,
|
||||
ncclProfilerProxyCtrlWakeup,
|
||||
ncclProfilerProxyCtrlAppend,
|
||||
ncclProfilerProxyCtrlAppendEnd,
|
||||
} ncclProfilerEventState_v1_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
size_t transSize;
|
||||
int steps;
|
||||
} proxyOp;
|
||||
|
||||
struct {
|
||||
int appendedProxyOps;
|
||||
} proxyCtrl;
|
||||
} ncclProfilerEventStateArgs_v1_t;
|
||||
typedef ncclProfilerEventState_v2_t ncclProfilerEventState_v1_t;
|
||||
typedef ncclProfilerEventStateArgs_v2_t ncclProfilerEventStateArgs_v1_t;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
@@ -142,9 +98,4 @@ typedef struct {
|
||||
ncclResult_t (*finalize)(void* context);
|
||||
} ncclProfiler_v1_t;
|
||||
|
||||
typedef ncclProfilerEventDescr_v1_t ncclProfilerEventDescr_t;
|
||||
typedef ncclProfilerEventState_v1_t ncclProfilerEventState_t;
|
||||
typedef ncclProfilerEventStateArgs_v1_t ncclProfilerEventStateArgs_t;
|
||||
typedef ncclProfiler_v1_t ncclProfiler_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*************************************************************************
|
||||
* Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* See LICENSE.txt for license information
|
||||
************************************************************************/
|
||||
|
||||
#ifndef NCCL_PROFILER_V2_H_
|
||||
#define NCCL_PROFILER_V2_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum {
|
||||
ncclProfileGroup = (1 << 0), // group event type
|
||||
ncclProfileColl = (1 << 1), // host collective call event type
|
||||
ncclProfileP2p = (1 << 2), // host point-to-point call event type
|
||||
ncclProfileProxyOp = (1 << 3), // proxy operation event type
|
||||
ncclProfileProxyStep = (1 << 4), // proxy step event type
|
||||
ncclProfileProxyCtrl = (1 << 5), // proxy control event type
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t type; // event type descriptor: ncclProfileColl, ...
|
||||
void* parentObj; // pointer to the profiler parent object (for coll is the group)
|
||||
int rank; // originating rank
|
||||
union {
|
||||
struct {
|
||||
const char* name;
|
||||
uint64_t commHash;
|
||||
uint64_t seqNumber;
|
||||
const char* func;
|
||||
void const* sendBuff;
|
||||
void* recvBuff;
|
||||
size_t count;
|
||||
int root;
|
||||
const char* datatype;
|
||||
size_t trafficBytes;
|
||||
uint8_t nMaxChannels;
|
||||
uint8_t nWarps;
|
||||
const char* algo;
|
||||
const char* proto;
|
||||
} coll;
|
||||
|
||||
struct {
|
||||
const char* name;
|
||||
uint64_t commHash;
|
||||
const char* func;
|
||||
void* buff;
|
||||
const char* datatype;
|
||||
size_t count;
|
||||
int peer;
|
||||
} p2p;
|
||||
|
||||
struct {
|
||||
pid_t pid; // pid of the originating process
|
||||
uint8_t channelId; // channel id for this proxy operation
|
||||
int peer; // remote rank for send/recv
|
||||
int nSteps; // number of steps for this proxy operation
|
||||
int chunkSize; // amount of data transferred by this proxy operation
|
||||
int isSend;
|
||||
} proxyOp;
|
||||
|
||||
struct {
|
||||
int step;
|
||||
} proxyStep;
|
||||
};
|
||||
} ncclProfilerEventDescr_v2_t;
|
||||
|
||||
typedef enum {
|
||||
ncclProfilerProxyOpSendPosted,
|
||||
ncclProfilerProxyOpSendRemFifoWait,
|
||||
ncclProfilerProxyOpSendTransmitted,
|
||||
ncclProfilerProxyOpSendDone,
|
||||
ncclProfilerProxyOpRecvPosted,
|
||||
ncclProfilerProxyOpRecvReceived,
|
||||
ncclProfilerProxyOpRecvTransmitted,
|
||||
ncclProfilerProxyOpRecvDone,
|
||||
|
||||
/* Legacy proxy profiler states */
|
||||
ncclProfilerProxyStepSendGPUWait,
|
||||
ncclProfilerProxyStepSendWait,
|
||||
ncclProfilerProxyStepRecvWait,
|
||||
ncclProfilerProxyStepRecvFlushWait,
|
||||
ncclProfilerProxyStepRecvGPUWait,
|
||||
|
||||
/* Legacy proxy control states */
|
||||
ncclProfilerProxyCtrlIdle,
|
||||
ncclProfilerProxyCtrlActive,
|
||||
ncclProfilerProxyCtrlSleep,
|
||||
ncclProfilerProxyCtrlWakeup,
|
||||
ncclProfilerProxyCtrlAppend,
|
||||
ncclProfilerProxyCtrlAppendEnd,
|
||||
} ncclProfilerEventState_v2_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
size_t transSize;
|
||||
int steps;
|
||||
} proxyOp;
|
||||
|
||||
struct {
|
||||
int appendedProxyOps;
|
||||
} proxyCtrl;
|
||||
} ncclProfilerEventStateArgs_v2_t;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
|
||||
// init - initialize the profiler plugin
|
||||
// Input
|
||||
// - context : opaque profiler context object for separating profiler behavior across comms
|
||||
// Output
|
||||
// - eActivationMask: bitmask of active events set by the plugin
|
||||
ncclResult_t (*init)(void** context, int* eActivationMask);
|
||||
|
||||
// startEvent - initialize and start a new event for the supplied event descriptor inside the eventset
|
||||
// Input
|
||||
// - context: opaque profiler context object
|
||||
// - eDescr : pointer to ncclProfilerEventDescr_t object
|
||||
// Output
|
||||
// - eHandle: return event handle for supplied event descriptor object
|
||||
ncclResult_t (*startEvent)(void* context, void** eHandle, ncclProfilerEventDescr_v2_t* eDescr);
|
||||
|
||||
// stopEvent - stop/finalize an event inside and event set
|
||||
// Input
|
||||
// - eHandle: handle to event object
|
||||
ncclResult_t (*stopEvent)(void* eHandle);
|
||||
|
||||
// recordEventState - record event state transitions and event attribute updates
|
||||
// Input
|
||||
// - eHandle : handle to event object created through startEvent
|
||||
// - eStateArgs: optional argument used to capture event attribute updates associated with the state transition
|
||||
// - eState : event state transition
|
||||
ncclResult_t (*recordEventState)(void* eHandle, ncclProfilerEventState_v2_t eState, ncclProfilerEventStateArgs_v2_t* eStateArgs);
|
||||
|
||||
// finalize - finalize the profiler plugin
|
||||
// Input
|
||||
// - context: opaque profiler context object
|
||||
ncclResult_t (*finalize)(void* context);
|
||||
} ncclProfiler_v2_t;
|
||||
|
||||
typedef ncclProfilerEventDescr_v2_t ncclProfilerEventDescr_t;
|
||||
typedef ncclProfilerEventState_v2_t ncclProfilerEventState_t;
|
||||
typedef ncclProfilerEventStateArgs_v2_t ncclProfilerEventStateArgs_t;
|
||||
typedef ncclProfiler_v2_t ncclProfiler_t;
|
||||
|
||||
#endif
|
||||
@@ -21,11 +21,18 @@
|
||||
static int initialized; // initialization counter for profiler
|
||||
static double startTime; // profiler start time
|
||||
|
||||
static int groupPoolSize = 16;
|
||||
static int collPoolSize = 16;
|
||||
static int p2pPoolSize = 1024;
|
||||
static int proxyCtrlPoolSize = 16;
|
||||
static int detachPoolSize = 128;
|
||||
static const int defaultEActivationMask = ncclProfileColl | ncclProfileP2p;
|
||||
static const int defaultGroupPoolSize = 16;
|
||||
static const int defaultCollPoolSize = 16;
|
||||
static const int defaultP2pPoolSize = 1024;
|
||||
static const int defaultProxyCtrlPoolSize = 16;
|
||||
static const int defaultDetachPoolSize = 128;
|
||||
|
||||
static int groupPoolSize;
|
||||
static int collPoolSize;
|
||||
static int p2pPoolSize;
|
||||
static int proxyCtrlPoolSize;
|
||||
static int detachPoolSize;
|
||||
static int detachPoolBase;
|
||||
static int detachPoolIndex;
|
||||
static int detachPoolDone;
|
||||
@@ -56,25 +63,25 @@ __hidden ncclResult_t exampleProfilerInit(void** context, int* eActivationMask)
|
||||
pthread_mutex_lock(&lock);
|
||||
if (__atomic_fetch_add(&initialized, 1, __ATOMIC_RELAXED) == 0) {
|
||||
// first thread initializes event mask, environment and detach pool
|
||||
__atomic_store_n(eActivationMask, ncclProfileColl | ncclProfileP2p, __ATOMIC_RELAXED);
|
||||
if (getenv("NCCL_PROFILE_EVENT_MASK")) {
|
||||
__atomic_store_n(eActivationMask, atoi(getenv("NCCL_PROFILE_EVENT_MASK")), __ATOMIC_RELAXED);
|
||||
}
|
||||
if (getenv("NCCL_PROFILE_GROUP_POOL_SIZE")) {
|
||||
groupPoolSize = atoi(getenv("NCCL_PROFILE_GROUP_POOL_SIZE"));
|
||||
}
|
||||
if (getenv("NCCL_PROFILE_COLL_POOL_SIZE")) {
|
||||
collPoolSize = atoi(getenv("NCCL_PROFILE_COLL_POOL_SIZE"));
|
||||
}
|
||||
if (getenv("NCCL_PROFILE_P2P_POOL_SIZE")) {
|
||||
p2pPoolSize = atoi(getenv("NCCL_PROFILE_P2P_POOL_SIZE"));
|
||||
}
|
||||
if (getenv("NCCL_PROFILE_PROXY_CTRL_POOL_SIZE")) {
|
||||
proxyCtrlPoolSize = atoi(getenv("NCCL_PROFILE_PROXY_CTRL_POOL_SIZE"));
|
||||
}
|
||||
if (getenv("NCCL_PROFILE_PROXY_DETACH_POOL_SIZE")) {
|
||||
detachPoolSize = atoi(getenv("NCCL_PROFILE_PROXY_DETACH_POOL_SIZE"));
|
||||
}
|
||||
const char* str;
|
||||
str = getenv("NCCL_PROFILE_EVENT_MASK");
|
||||
__atomic_store_n(eActivationMask, str ? atoi(str) : defaultEActivationMask, __ATOMIC_RELAXED);
|
||||
|
||||
str = getenv("NCCL_PROFILE_GROUP_POOL_SIZE");
|
||||
groupPoolSize = str ? atoi(str) : defaultGroupPoolSize;
|
||||
|
||||
str = getenv("NCCL_PROFILE_COLL_POOL_SIZE");
|
||||
collPoolSize = str ? atoi(str) : defaultCollPoolSize;
|
||||
|
||||
str = getenv("NCCL_PROFILE_P2P_POOL_SIZE");
|
||||
p2pPoolSize = str ? atoi(str) : defaultP2pPoolSize;
|
||||
|
||||
str = getenv("NCCL_PROFILE_PROXY_CTRL_POOL_SIZE");
|
||||
proxyCtrlPoolSize = str ? atoi(str) : defaultProxyCtrlPoolSize;
|
||||
|
||||
str = getenv("NCCL_PROFILE_PROXY_DETACH_POOL_SIZE");
|
||||
detachPoolSize = str ? atoi(str) : defaultDetachPoolSize;
|
||||
|
||||
// detach pool is used to store PXN proxyOps and is shared among threads
|
||||
detachPool = (struct proxyOp *)calloc(detachPoolSize, sizeof(*detachPool));
|
||||
if (detachPool == NULL) {
|
||||
@@ -107,6 +114,13 @@ __hidden ncclResult_t exampleProfilerInit(void** context, int* eActivationMask)
|
||||
ctx->proxyCtrlPool = (struct proxyCtrl *)calloc(proxyCtrlPoolSize, sizeof(*ctx->proxyCtrlPool));
|
||||
if (ctx->proxyCtrlPool == NULL) goto fail;
|
||||
|
||||
// Print event pool sizes for debugging
|
||||
//fprintf(stdout, "Profiler: Group pool size (bytes): %lu\n", sizeof(struct group)*groupPoolSize);
|
||||
//fprintf(stdout, "Profiler: Coll pool size (bytes): %lu\n", sizeof(struct collective)*collPoolSize);
|
||||
//fprintf(stdout, "Profiler: P2p pool size (bytes): %lu\n", sizeof(struct p2p)*p2pPoolSize);
|
||||
//fprintf(stdout, "Profiler: Proxy pool size (bytes): %lu\n", sizeof(struct proxyCtrl)*proxyCtrlPoolSize);
|
||||
//fprintf(stdout, "Profiler: PXN pool size (bytes): %lu\n", sizeof(struct proxyOp)*detachPoolSize);
|
||||
|
||||
*context = ctx;
|
||||
return ncclSuccess;
|
||||
|
||||
@@ -154,7 +168,7 @@ __hidden ncclResult_t exampleProfilerFinalize(void* context) {
|
||||
free(ctx);
|
||||
|
||||
// last thread cleans up shared detach pool
|
||||
if (__atomic_fetch_sub(&initialized, 1, __ATOMIC_RELAXED) - 1 == 0) {
|
||||
if (__atomic_sub_fetch(&initialized, 1, __ATOMIC_RELAXED) == 0) {
|
||||
start = (detachPoolIndex - detachPoolSize >= 0) ? detachPoolIndex - detachPoolSize : 0;
|
||||
end = detachPoolIndex;
|
||||
for (int i = start; i < end; i++) {
|
||||
@@ -171,7 +185,7 @@ __hidden ncclResult_t exampleProfilerFinalize(void* context) {
|
||||
|
||||
__hidden void updateEvent(void* handle);
|
||||
|
||||
__hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, ncclProfilerEventDescr_v1_t* eDescr) {
|
||||
__hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, ncclProfilerEventDescr_t* eDescr) {
|
||||
*eHandle = NULL;
|
||||
struct context* ctx = (struct context *)context;
|
||||
if (eDescr->type == ncclProfileGroup) {
|
||||
@@ -185,14 +199,15 @@ __hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, n
|
||||
if (base->type == ncclProfileColl) {
|
||||
struct collective* c = (struct collective *)base;
|
||||
// reset event proxyOps & proxySteps
|
||||
memset(c->send, 0, sizeof(struct proxyOp)*MAX_CHANNELS);
|
||||
memset(c->recv, 0, sizeof(struct proxyOp)*MAX_CHANNELS);
|
||||
memset(c->send, 0, sizeof(struct proxyOp)*MAX_CHANNELS*MAX_OPS);
|
||||
memset(c->recv, 0, sizeof(struct proxyOp)*MAX_CHANNELS*MAX_OPS);
|
||||
memset(c->nProxyOps, 0, sizeof(int)*MAX_CHANNELS);
|
||||
// release collective events in the group and return them to the collective pool
|
||||
__atomic_fetch_add(&ctx->collPoolBase, 1, __ATOMIC_RELAXED);
|
||||
} else if (base->type == ncclProfileP2p) {
|
||||
struct p2p* p = (struct p2p *)base;
|
||||
// reset event proxyOp and proxySteps
|
||||
memset(&p->op, 0, sizeof(struct proxyOp));
|
||||
memset(&p->op, 0, sizeof(struct proxyOp)*MAX_CHANNELS);
|
||||
// release p2p events in the group and return them to the p2p pool
|
||||
__atomic_fetch_add(&ctx->p2pPoolBase, 1, __ATOMIC_RELAXED);
|
||||
}
|
||||
@@ -203,7 +218,6 @@ __hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, n
|
||||
return ncclSuccess;
|
||||
}
|
||||
event->type = ncclProfileGroup;
|
||||
__atomic_store_n(&event->refCount, 1, __ATOMIC_RELAXED);
|
||||
event->ctx = ctx;
|
||||
event->groupId = groupId;
|
||||
event->startTs = gettime() - startTime;
|
||||
@@ -238,14 +252,11 @@ __hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, n
|
||||
event->count = eDescr->coll.count;
|
||||
event->root = eDescr->coll.root;
|
||||
event->datatype = eDescr->coll.datatype;
|
||||
event->op = eDescr->coll.op;
|
||||
event->trafficBytes = eDescr->coll.trafficBytes;
|
||||
event->nMaxChannels = eDescr->coll.nMaxChannels;
|
||||
event->nWarps = eDescr->coll.nWarps;
|
||||
event->algo = eDescr->coll.algo;
|
||||
event->proto = eDescr->coll.proto;
|
||||
event->isCollnet = eDescr->coll.isCollnet;
|
||||
event->isNvls = eDescr->coll.isNvls;
|
||||
*eHandle = event;
|
||||
taskEventQueueEnqueue(parent, (struct taskEventBase *)event);
|
||||
// increment the group ref counter so the event will staty open
|
||||
@@ -326,9 +337,13 @@ __hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, n
|
||||
|
||||
if (eventBase->type == ncclProfileColl) {
|
||||
struct collective* parent = (struct collective *)eDescr->parentObj;
|
||||
struct proxyOp* event = (eDescr->proxyOp.isSend) ? &parent->send[eDescr->proxyOp.channelId] : &parent->recv[eDescr->proxyOp.channelId];
|
||||
int channelId = eDescr->proxyOp.channelId;
|
||||
struct proxyOp* event = (eDescr->proxyOp.isSend) ?
|
||||
&parent->send[channelId][parent->nProxyOps[channelId]++] :
|
||||
&parent->recv[channelId][parent->nProxyOps[channelId]++];
|
||||
|
||||
event->type = ncclProfileProxyOp;
|
||||
event->channelId = eDescr->proxyOp.channelId;
|
||||
event->channelId = channelId;
|
||||
event->pid = eDescr->proxyOp.pid;
|
||||
event->rank = eDescr->rank;
|
||||
event->peer = eDescr->proxyOp.peer;
|
||||
@@ -338,13 +353,14 @@ __hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, n
|
||||
event->parent = eventBase;
|
||||
event->startTs = gettime() - startTime;
|
||||
*eHandle = event;
|
||||
__atomic_store_n(&parent->base.refCount, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&parent->base.refCount, 1, __ATOMIC_RELAXED);
|
||||
debugEvent(event, "ProxyOpStart");
|
||||
} else { // ncclProfileP2p
|
||||
struct p2p* parent = (struct p2p *)eDescr->parentObj;
|
||||
struct proxyOp* event = &parent->op;
|
||||
int channelId = eDescr->proxyOp.channelId;
|
||||
struct proxyOp* event = &parent->op[channelId];
|
||||
event->type = ncclProfileProxyOp;
|
||||
event->channelId = eDescr->proxyOp.channelId;
|
||||
event->channelId = channelId;
|
||||
event->pid = eDescr->proxyOp.pid;
|
||||
event->rank = eDescr->rank;
|
||||
event->peer = eDescr->proxyOp.peer;
|
||||
@@ -354,7 +370,7 @@ __hidden ncclResult_t exampleProfilerStartEvent(void* context, void** eHandle, n
|
||||
event->parent = eventBase;
|
||||
event->startTs = gettime() - startTime;
|
||||
*eHandle = event;
|
||||
__atomic_store_n(&parent->base.refCount, 1, __ATOMIC_RELAXED);
|
||||
__atomic_fetch_add(&parent->base.refCount, 1, __ATOMIC_RELAXED);
|
||||
debugEvent(event, "ProxyOpStart");
|
||||
}
|
||||
} else if (eDescr->type == ncclProfileProxyStep) {
|
||||
@@ -379,7 +395,7 @@ void updateEvent(void* handle) {
|
||||
uint8_t type = *(uint8_t *)handle;
|
||||
if (type == ncclProfileGroup) {
|
||||
struct group* event = (struct group *)handle;
|
||||
if (__atomic_fetch_sub(&event->refCount, 1, __ATOMIC_RELAXED) == 1) {
|
||||
if (__atomic_sub_fetch(&event->refCount, 1, __ATOMIC_RELAXED) == 0) {
|
||||
event->stopTs = gettime() - startTime;
|
||||
// return group event to the pool
|
||||
__atomic_fetch_add(&event->ctx->groupPoolBase, 1, __ATOMIC_RELAXED);
|
||||
@@ -387,7 +403,7 @@ void updateEvent(void* handle) {
|
||||
debugEvent(event, "GroupStop");
|
||||
} else if (type == ncclProfileColl) {
|
||||
struct collective* event = (struct collective *)handle;
|
||||
if (__atomic_fetch_sub(&event->base.refCount, 1, __ATOMIC_RELAXED) == 1) {
|
||||
if (__atomic_sub_fetch(&event->base.refCount, 1, __ATOMIC_RELAXED) == 0) {
|
||||
event->base.stopTs = gettime() - startTime;
|
||||
debugEvent(event, "CollStop");
|
||||
updateEvent(event->base.parent);
|
||||
@@ -396,7 +412,7 @@ void updateEvent(void* handle) {
|
||||
debugEvent(event, "CollStop");
|
||||
} else if (type == ncclProfileP2p) {
|
||||
struct p2p* event = (struct p2p *)handle;
|
||||
if (__atomic_fetch_sub(&event->base.refCount, 1, __ATOMIC_RELAXED) == 1) {
|
||||
if (__atomic_sub_fetch(&event->base.refCount, 1, __ATOMIC_RELAXED) == 0) {
|
||||
event->base.stopTs = gettime() - startTime;
|
||||
debugEvent(event, "P2pStop");
|
||||
updateEvent(event->base.parent);
|
||||
@@ -408,7 +424,7 @@ void updateEvent(void* handle) {
|
||||
event->stopTs = gettime() - startTime;
|
||||
if (event->pid != pid) {
|
||||
// only for proxyOps that don't have a parent collective/p2p (i.e., PXN)
|
||||
int done = __atomic_fetch_add(&detachPoolDone, 1, __ATOMIC_RELAXED) + 1;
|
||||
int done = __atomic_add_fetch(&detachPoolDone, 1, __ATOMIC_RELAXED);
|
||||
if (done == detachPoolSize) {
|
||||
// reset the event completed (done) counter
|
||||
__atomic_store_n(&detachPoolDone, 0, __ATOMIC_RELAXED);
|
||||
@@ -451,12 +467,20 @@ __hidden ncclResult_t exampleProfilerStopEvent(void* eHandle) {
|
||||
struct collective* event = (struct collective *)eHandle;
|
||||
event->base.stopTs = gettime() - startTime;
|
||||
return ncclSuccess;
|
||||
} else if (type == ncclProfileP2p) {
|
||||
// stopping the p2p event in NCCL core does not
|
||||
// mean the p2p has completed. It means the p2p
|
||||
// was submitted/enqueued so we need to keep the event open
|
||||
struct p2p* event = (struct p2p *)eHandle;
|
||||
event->base.stopTs = gettime() - startTime;
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
updateEvent(eHandle);
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
__hidden ncclResult_t exampleProfilerRecordEventState(void* eHandle, ncclProfilerEventState_v1_t eState, ncclProfilerEventStateArgs_v1_t* eStateArgs) {
|
||||
__hidden ncclResult_t exampleProfilerRecordEventState(void* eHandle, ncclProfilerEventState_t eState, ncclProfilerEventStateArgs_t* eStateArgs) {
|
||||
// the event handle might be null if we run out of events
|
||||
if (eHandle == NULL) return ncclSuccess;
|
||||
|
||||
@@ -482,7 +506,7 @@ __hidden ncclResult_t exampleProfilerRecordEventState(void* eHandle, ncclProfile
|
||||
return ncclSuccess;
|
||||
}
|
||||
|
||||
ncclProfiler_v1_t ncclProfiler_v1 = {
|
||||
ncclProfiler_t ncclProfiler_v2 = {
|
||||
"Example-profiler",
|
||||
exampleProfilerInit,
|
||||
exampleProfilerStartEvent,
|
||||
|
||||
@@ -11,56 +11,6 @@
|
||||
|
||||
#define __hidden __attribute__ ((visibility("hidden")))
|
||||
|
||||
__hidden const char* ncclFuncToString(int func) {
|
||||
switch(func) {
|
||||
case 0:
|
||||
return "ncclBroadcast";
|
||||
case 1:
|
||||
return "ncclReduce";
|
||||
case 2:
|
||||
return "ncclAllGather";
|
||||
case 3:
|
||||
return "ncclReduceScatter";
|
||||
case 4:
|
||||
return "ncclAllReduce";
|
||||
case 5:
|
||||
return "ncclSendRecv";
|
||||
case 6:
|
||||
return "ncclSend";
|
||||
case 7:
|
||||
return "ncclRecv";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__hidden const char* ncclAlgoToString(int algo) {
|
||||
switch(algo) {
|
||||
case 0:
|
||||
return "Tree";
|
||||
case 1:
|
||||
return "Ring";
|
||||
case 2:
|
||||
return "CollnetDirect";
|
||||
case 3:
|
||||
return "CollnetChain";
|
||||
case 4:
|
||||
return "Nvls";
|
||||
case 5:
|
||||
return "NvlsTree";
|
||||
}
|
||||
}
|
||||
|
||||
__hidden const char* ncclProtoToString(int proto) {
|
||||
switch(proto) {
|
||||
case 0:
|
||||
return "LL";
|
||||
case 1:
|
||||
return "LL128";
|
||||
case 2:
|
||||
return "Simple";
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: chrome tracing asynchronous events (following used) allow event nesting for events that have same id and category
|
||||
// It appears that nesting more than three events causes issues. Therefore, every event is given an increasing id and a
|
||||
// category that matches the type of event (GROUP, COLL, P2P, PROXY, NET)
|
||||
@@ -77,24 +27,24 @@ __hidden void printGroupEventTrailer(FILE* fh, struct group* event) {
|
||||
|
||||
static __thread int collId;
|
||||
__hidden void printCollEventHeader(FILE* fh, struct collective* event) {
|
||||
fprintf(fh, "{\"name\": \"%s\", \"cat\": \"COLL\", \"ph\": \"b\", \"id\": %d, \"pid\": %d, \"tid\": %d, \"ts\": %f, \"args\": {\"SeqNum\": %lu, \"CommHash\": %lu, \"Rank\": %d, \"Count\": %lu, \"Datatype\": %d, \"Algorithm\": \"%s\", \"Protocol\": \"%s\", \"nMaxChannels\": %d}},\n",
|
||||
ncclFuncToString(event->base.func), collId, getpid(), 1, event->base.startTs, event->seqNumber, event->base.commHash, event->base.rank, event->count, event->datatype, ncclAlgoToString(event->algo), ncclProtoToString(event->proto), event->nMaxChannels);
|
||||
fprintf(fh, "{\"name\": \"%s\", \"cat\": \"COLL\", \"ph\": \"b\", \"id\": %d, \"pid\": %d, \"tid\": %d, \"ts\": %f, \"args\": {\"SeqNum\": %lu, \"CommHash\": %lu, \"Rank\": %d, \"Count\": %lu, \"Datatype\": \"%s\", \"Algorithm\": \"%s\", \"Protocol\": \"%s\", \"nMaxChannels\": %d}},\n",
|
||||
event->base.func, collId, getpid(), 1, event->base.startTs, event->seqNumber, event->base.commHash, event->base.rank, event->count, event->datatype, event->algo, event->proto, event->nMaxChannels);
|
||||
}
|
||||
|
||||
__hidden void printCollEventTrailer(FILE* fh, struct collective* event) {
|
||||
fprintf(fh, "{\"name\": \"%s\", \"cat\": \"COLL\", \"ph\": \"e\", \"id\": %d, \"pid\": %d, \"tid\": %d, \"ts\": %f},\n",
|
||||
ncclFuncToString(event->base.func), collId++, getpid(), 1, event->base.stopTs);
|
||||
event->base.func, collId++, getpid(), 1, event->base.stopTs);
|
||||
}
|
||||
|
||||
static __thread int p2pId;
|
||||
__hidden void printP2pEventHeader(FILE* fh, struct p2p* event) {
|
||||
fprintf(fh, "{\"name\": \"%s\", \"cat\": \"P2P\", \"ph\": \"b\", \"id\": %d, \"pid\": %d, \"tid\": %d, \"ts\": %f, \"args\": {\"CommHash\": %lu, \"Rank\": %d, \"Peer\": %d, \"Count\": %lu, \"Datatype\": %d}},\n",
|
||||
ncclFuncToString(event->base.func), p2pId, getpid(), 1, event->base.startTs, event->base.commHash, event->base.rank, event->peer, event->count, event->datatype);
|
||||
fprintf(fh, "{\"name\": \"%s\", \"cat\": \"P2P\", \"ph\": \"b\", \"id\": %d, \"pid\": %d, \"tid\": %d, \"ts\": %f, \"args\": {\"CommHash\": %lu, \"Rank\": %d, \"Peer\": %d, \"Count\": %lu, \"Datatype\": \"%s\"}},\n",
|
||||
event->base.func, p2pId, getpid(), 1, event->base.startTs, event->base.commHash, event->base.rank, event->peer, event->count, event->datatype);
|
||||
}
|
||||
|
||||
__hidden void printP2pEventTrailer(FILE* fh, struct p2p* event) {
|
||||
fprintf(fh, "{\"name\": \"%s\", \"cat\": \"P2P\", \"ph\": \"e\", \"id\": %d, \"pid\": %d, \"tid\": %d, \"ts\": %f},\n",
|
||||
ncclFuncToString(event->base.func), p2pId++, getpid(), 1, event->base.stopTs);
|
||||
event->base.func, p2pId++, getpid(), 1, event->base.stopTs);
|
||||
}
|
||||
|
||||
static __thread int proxyOpId;
|
||||
@@ -250,14 +200,18 @@ void printEvent(FILE* fh, void* handle) {
|
||||
struct collective* c = (struct collective *)handle;
|
||||
printCollEventHeader(fh, c);
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
printEvent(fh, &c->send[i]);
|
||||
printEvent(fh, &c->recv[i]);
|
||||
for (int j = 0; j < c->nProxyOps[i]; j++) {
|
||||
printEvent(fh, &c->send[i][j]);
|
||||
printEvent(fh, &c->recv[i][j]);
|
||||
}
|
||||
}
|
||||
printCollEventTrailer(fh, c);
|
||||
} else if (type == ncclProfileP2p) {
|
||||
struct p2p* p = (struct p2p *)handle;
|
||||
printP2pEventHeader(fh, p);
|
||||
printEvent(fh, &p->op);
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
printEvent(fh, &p->op[i]);
|
||||
}
|
||||
printP2pEventTrailer(fh, p);
|
||||
} else if (type == ncclProfileProxyOp) {
|
||||
struct proxyOp* p = (struct proxyOp *)handle;
|
||||
|
||||
Reference in New Issue
Block a user