2019-11-19 14:57:39 -08:00
/*************************************************************************
2020-01-16 16:02:42 -08:00
* Copyright (c) 2016-2020, NVIDIA CORPORATION. All rights reserved.
2020-01-15 17:54:27 -07:00
* Modifications Copyright (c) 2019-2020 Advanced Micro Devices, Inc. All rights reserved.
2019-11-19 14:57:39 -08:00
*
* See LICENSE.txt for license information
************************************************************************/
#include "core.h"
#include "devcomm.h"
#include "comm.h"
#include "topo.h"
NCCL_PARAM ( Nthreads , "NTHREADS" , - 2 );
NCCL_PARAM ( Ll128Nthreads , "LL128_NTHREADS" , - 2 );
static int getNthreads ( const char * name , int env , int min , int max , int def ) {
int nt = env ;
if ( nt > 0 ) {
if ( nt % WARP_SIZE != 0 ) {
WARN ( "Invalid %s %d (must be a multiple of %d)" , name , nt , WARP_SIZE );
nt = max ;
} else if ( nt > max ) {
WARN ( "Invalid %s %d (maximum %d)." , name , nt , max );
nt = max ;
} else if ( nt < min ) {
WARN ( "Invalid %s %d (minimum %d)." , name , nt , min );
nt = min ;
}
} else {
nt = def ;
}
return nt ;
}
ncclResult_t parseList ( const char * str , const char * elems [], int nelems , int * list ) {
int def , set ;
if ( str [ 0 ] == '^' ) {
def = 1 ; set = 0 ; str ++ ;
} else {
def = 0 ; set = 1 ;
}
for ( int i = 0 ; i < nelems ; i ++ ) list [ i ] = def ;
char * tokStr = strdup ( str );
char * tmpStr ;
char * token = strtok_r ( tokStr , "," , & tmpStr );
while ( token ) {
for ( int i = 0 ; i < nelems ; i ++ )
if ( strcasecmp ( token , elems [ i ]) == 0 ) list [ i ] = set ;
token = strtok_r ( NULL , "," , & tmpStr );
}
free ( tokStr );
return ncclSuccess ;
}
// Latencies in us, Bandwidths in GB/s
// Tree { LL, LL128, Simple } , Ring { LL, LL128, Simple }
2021-02-23 21:41:26 +00:00
static const float baseLat [ NCCL_NUM_ALGORITHMS ][ NCCL_NUM_PROTOCOLS ] = { { 39.0 , 39.0 , 49.0 }, { 21.0 , 21.0 , 30.0 }, { 37.9 , 37.9 , 40.4 } };
2019-11-19 14:57:39 -08:00
// NVLink, PCI, Network
#define NCCL_HW_NVLINK 0
#define NCCL_HW_PCI 1
#define NCCL_HW_NET 2
// Tree/Simple is the latency a 256kB chunk, which is ~ base lat + 256k/12GB/s (+ 256k/12GB/s for the network).
static const float hwLat [ 3 ][ NCCL_NUM_ALGORITHMS ][ NCCL_NUM_PROTOCOLS ] =
{ /* NVLINK */
2021-03-25 20:59:32 -07:00
{ /* Tree (LL/LL128/Simple)*/ { 2.5 , 2.5 , 5.5 }, /* Ring (LL/LL128/Simple)*/ { 2.5 , 2.5 , 5 }, /* CollNet (LL/LL128/Simple)*/ { 1.1 , 1.1 , 3.3 } },
2019-11-19 14:57:39 -08:00
/* PCI */
2021-03-25 20:59:32 -07:00
{ /* Tree (LL/LL128/Simple)*/ { 2.2 , 2.2 , 5.7 }, /* Ring (LL/LL128/Simple)*/ { 1.3 , 1.3 , 1.9 }, /* CollNet (LL/LL128/Simple)*/ { 1.1 , 1.1 , 1.7 } },
2019-11-19 14:57:39 -08:00
/* NET */
2021-03-25 20:59:32 -07:00
{ /* Tree (LL/LL128/Simple)*/ { 28.0 , 28.0 , 66.0 }, /* Ring (LL/LL128/Simple)*/ { 8.5 , 8.5 , 19.0 }, /* CollNet (LL/LL128/Simple)*/ { 6.5 , 6.5 , 14.5 } }
2019-11-19 14:57:39 -08:00
};
2020-05-12 14:40:18 -07:00
// LL128 max BW (per channel) for the different collectives
2020-09-04 14:35:05 -07:00
// ncclFuncBroadcast, ncclFuncReduce, ncclFuncAllGather, ncclFuncReduceScatter, ncclFuncAllReduce
static const double ll128MaxBwPerCh [ NCCL_NUM_FUNCTIONS ] = { 18.8 , 12.0 , 18.3 , 15.2 , 16.9 };
static const double llMaxBws [ 2 ][ 3 ] = { /* Volta-N1/Intel-N2/Intel-N4) */ { 39.0 , 39.0 , 20.4 }, /* Ampere-N1/AMD-N2/AMD-N4) */ { 87.7 , 22.5 /*avg of ring & tree*/ , 19.0 } };
static const double perChMaxTreeBws [ 2 ][ 3 ] = { /* Volta (N1/N2/N4) */ { 26.5 , 18.5 , 10.0 }, /* Ampere (N1/N2/N4) */ { 24.0 , 22.5 , 16.0 } };
2019-11-19 14:57:39 -08:00
2020-05-12 14:40:18 -07:00
ncclResult_t ncclTopoTuneModel ( struct ncclComm * comm , int minCompCap , int maxCompCap , struct ncclTopoGraph * treeGraph , struct ncclTopoGraph * ringGraph , struct ncclTopoGraph * collNetGraph ) {
2020-09-04 14:35:05 -07:00
int simpleDefaultThreads = ( ringGraph -> speedIntra * ringGraph -> nChannels <= PCI_WIDTH ) ? 256 : NCCL_SIMPLE_MAX_NTHREADS ;
2020-01-16 16:02:42 -08:00
comm -> maxThreads [ NCCL_ALGO_RING ][ NCCL_PROTO_SIMPLE ] =
2020-12-01 11:33:47 -05:00
#if defined(__HIP_PLATFORM_HCC__) || defined(__HCC__) || defined(__HIPCC__)
2020-04-01 13:21:38 -07:00
getNthreads ( "NCCL_NTHREADS" , ncclParamNthreads (), 4 * WARP_SIZE , NCCL_MAX_NTHREADS , simpleDefaultThreads );
2020-01-16 16:02:42 -08:00
comm -> maxThreads [ NCCL_ALGO_TREE ][ NCCL_PROTO_SIMPLE ] = comm -> maxThreads [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_SIMPLE ] =
2020-04-01 13:21:38 -07:00
getNthreads ( "NCCL_NTHREADS" , ncclParamNthreads (), 4 * WARP_SIZE , NCCL_MAX_NTHREADS , NCCL_MAX_NTHREADS );
2020-01-16 16:02:42 -08:00
comm -> maxThreads [ NCCL_ALGO_RING ][ NCCL_PROTO_LL ] = comm -> maxThreads [ NCCL_ALGO_TREE ][ NCCL_PROTO_LL ] = comm -> maxThreads [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_LL ] =
2020-04-01 13:21:38 -07:00
getNthreads ( "NCCL_NTHREADS" , ncclParamNthreads (), 4 * WARP_SIZE , NCCL_MAX_NTHREADS , NCCL_MAX_NTHREADS );
2020-12-01 11:33:47 -05:00
#else
2020-09-04 14:35:05 -07:00
getNthreads ( "NCCL_NTHREADS" , ncclParamNthreads (), 2 * WARP_SIZE , NCCL_SIMPLE_MAX_NTHREADS , simpleDefaultThreads );
2020-01-16 16:02:42 -08:00
comm -> maxThreads [ NCCL_ALGO_TREE ][ NCCL_PROTO_SIMPLE ] = comm -> maxThreads [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_SIMPLE ] =
2020-09-04 14:35:05 -07:00
getNthreads ( "NCCL_NTHREADS" , ncclParamNthreads (), 2 * WARP_SIZE , NCCL_SIMPLE_MAX_NTHREADS , NCCL_SIMPLE_MAX_NTHREADS );
2020-01-16 16:02:42 -08:00
comm -> maxThreads [ NCCL_ALGO_RING ][ NCCL_PROTO_LL ] = comm -> maxThreads [ NCCL_ALGO_TREE ][ NCCL_PROTO_LL ] = comm -> maxThreads [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_LL ] =
2020-09-04 14:35:05 -07:00
getNthreads ( "NCCL_NTHREADS" , ncclParamNthreads (), 2 * WARP_SIZE , NCCL_LL_MAX_NTHREADS , NCCL_LL_MAX_NTHREADS );
2020-12-01 11:33:47 -05:00
#endif
2020-01-16 16:02:42 -08:00
comm -> maxThreads [ NCCL_ALGO_RING ][ NCCL_PROTO_LL128 ] = comm -> maxThreads [ NCCL_ALGO_TREE ][ NCCL_PROTO_LL128 ] = comm -> maxThreads [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_LL128 ] =
getNthreads ( "NCCL_LL128_NTHREADS" , ncclParamLl128Nthreads (), NCCL_LL128_MAX_NTHREADS / 4 , NCCL_LL128_MAX_NTHREADS , NCCL_LL128_MAX_NTHREADS );
2019-11-19 14:57:39 -08:00
2020-09-04 14:35:05 -07:00
int nNodes = comm -> nNodes ;
int nRanks = comm -> nRanks ;
if ( nRanks <= 1 ) return ncclSuccess ;
2019-11-19 14:57:39 -08:00
2020-05-12 14:40:18 -07:00
int compCap80 = minCompCap == 80 && maxCompCap == 80 ? 1 : 0 ;
2020-09-04 14:35:05 -07:00
int cpuArch , cpuVendor , cpuModel ;
NCCLCHECK ( ncclTopoCpuType ( comm -> topo , & cpuArch , & cpuVendor , & cpuModel ));
int index2 = nNodes <= 2 ? nNodes - 1 : 2 ;
// LL: for single node, we look at GPU type; for multi-node, we look at CPU type
int index1 = nNodes == 1 ? compCap80 : cpuVendor == NCCL_TOPO_CPU_VENDOR_AMD ? 1 : 0 ;
double llMaxBw = llMaxBws [ index1 ][ index2 ];
double perChMaxTreeBw = perChMaxTreeBws [ compCap80 ][ index2 ];
float ppn = ( float ) nRanks / nNodes ; // if ppn < 2, then we are sending/receiving at the same GPU through the NIC, apply some bw discount
2020-01-16 16:02:42 -08:00
struct ncclTopoGraph * graphs [ NCCL_NUM_ALGORITHMS ] = { treeGraph , ringGraph , collNetGraph };
int intraHw [ NCCL_NUM_ALGORITHMS ], hw [ NCCL_NUM_ALGORITHMS ];
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) intraHw [ a ] = graphs [ a ] -> typeIntra == LINK_NVL ? NCCL_HW_NVLINK : NCCL_HW_PCI ;
2020-09-04 14:35:05 -07:00
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) hw [ a ] = nNodes == 1 ? intraHw [ a ] : NCCL_HW_NET ;
2019-11-19 14:57:39 -08:00
for ( int coll = 0 ; coll < NCCL_NUM_FUNCTIONS ; coll ++ ) {
2020-09-04 14:35:05 -07:00
int nsteps = coll == ncclFuncAllReduce ? 2 * ( nRanks - 1 ) :
coll == ncclFuncReduceScatter || coll == ncclFuncAllGather ? nRanks - 1 :
nRanks ;
int nInterSteps = coll == ncclFuncAllReduce ? 2 * ( nNodes - 1 ) :
coll == ncclFuncReduceScatter || coll == ncclFuncAllGather ? nNodes - 1 :
nNodes ;
2019-11-19 14:57:39 -08:00
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) {
2020-09-04 14:35:05 -07:00
if ( coll != ncclFuncAllReduce && a != NCCL_ALGO_RING ) continue ;
2019-11-19 14:57:39 -08:00
for ( int p = 0 ; p < NCCL_NUM_PROTOCOLS ; p ++ ) {
2020-09-04 14:35:05 -07:00
float speed = nNodes <= 2 || a == NCCL_ALGO_COLLNET ? graphs [ a ] -> speedIntra : graphs [ a ] -> speedInter ;
2020-01-16 16:02:42 -08:00
float busBw = graphs [ a ] -> nChannels * speed ;
2019-11-19 14:57:39 -08:00
// Various model refinements
2020-12-01 11:33:47 -05:00
#if defined(__HIP_PLATFORM_HCC__) || defined(__HCC__) || defined(__HIPCC__)
2019-11-26 16:33:13 -08:00
if ( a == NCCL_ALGO_RING && p == NCCL_PROTO_LL ) busBw *= 1.0 / 5.0 ;
2020-05-12 14:40:18 -07:00
if ( a == NCCL_ALGO_RING && p == NCCL_PROTO_LL128 ) busBw = std :: min ( busBw * ( ppn < 2 ? 0.7 : 0.92 /*120.0/128.0*/ ), ll128MaxBwPerCh [ coll ] * graphs [ a ] -> nChannels );
double maxTreeBw = comm -> nNodes > 2 ?
compCap80 && p == NCCL_PROTO_LL128 ? 105.0 : 80.0 :
compCap80 && p == NCCL_PROTO_LL128 ? 130.0 : 110.0 ;
2019-11-26 16:33:13 -08:00
if ( a == NCCL_ALGO_TREE ) busBw = std :: min ( busBw * .27 , comm -> nNodes > 1 ? 70.0 : 90.0 );
if ( a == NCCL_ALGO_TREE && p == NCCL_PROTO_LL ) busBw *= 1.0 / 2.3 ;
2020-05-12 14:40:18 -07:00
if ( a == NCCL_ALGO_TREE && p == NCCL_PROTO_LL128 ) busBw = std :: min ( busBw * ( comm -> nNodes == 1 ? 7.0 / 9.0 : 0.915 /*120.0/128.0*/ ), ll128MaxBwPerCh [ coll ] * graphs [ a ] -> nChannels * 7.0 / 9.0 );
2020-12-01 11:33:47 -05:00
#else
2020-06-22 09:36:20 -07:00
if ( compCap80 ) busBw = std :: min ( busBw , 235.0f );
2020-09-04 14:35:05 -07:00
if ( a == NCCL_ALGO_RING && p == NCCL_PROTO_LL ) { busBw = std :: min ( llMaxBw , busBw * (( nNodes > 1 || coll == ncclFuncAllReduce || coll == ncclFuncReduce ) ? 1.0 / 4.0 : 1.0 / 3.0 )); }
2020-05-12 14:40:18 -07:00
if ( a == NCCL_ALGO_RING && p == NCCL_PROTO_LL128 ) busBw = std :: min ( busBw * ( ppn < 2 ? 0.7 : 0.92 /*120.0/128.0*/ ), ll128MaxBwPerCh [ coll ] * graphs [ a ] -> nChannels );
2020-09-04 14:35:05 -07:00
if ( a == NCCL_ALGO_TREE ) busBw = std :: min ( busBw * .92 , graphs [ a ] -> nChannels * perChMaxTreeBw );
if ( a == NCCL_ALGO_TREE && p == NCCL_PROTO_LL ) busBw = std :: min ( busBw * 1.0 / 3.8 , llMaxBw );
if ( a == NCCL_ALGO_TREE && p == NCCL_PROTO_LL128 ) busBw = std :: min ( busBw * ( nNodes == 1 ? 7.0 / 9.0 : 0.915 /*120.0/128.0*/ ), ll128MaxBwPerCh [ coll ] * graphs [ a ] -> nChannels );
2020-12-01 11:33:47 -05:00
#endif
2020-01-16 16:02:42 -08:00
if ( a == NCCL_ALGO_COLLNET ) busBw *= .9 ;
2021-03-25 20:59:32 -07:00
if ( a == NCCL_ALGO_COLLNET && p == NCCL_PROTO_LL ) busBw *= 1.0 / 2.0 ; // Take into account that GDR read is disabled on both sides
2020-01-16 16:02:42 -08:00
if ( a == NCCL_ALGO_COLLNET && p == NCCL_PROTO_LL128 ) busBw = 0 ; // CollNet does not support LL128
2019-11-19 14:57:39 -08:00
// Convert bus BW to algorithm BW
2020-09-04 14:35:05 -07:00
float ratio = ( a != NCCL_ALGO_RING ) ? .5 : ( 1.0 * nRanks ) / nsteps ;
2019-11-19 14:57:39 -08:00
comm -> bandwidths [ coll ][ a ][ p ] = busBw * ratio ;
comm -> latencies [ coll ][ a ][ p ] = baseLat [ a ][ p ];
2020-05-12 14:40:18 -07:00
float intraLat = hwLat [ intraHw [ a ]][ a ][ p ];
float interLat = hwLat [ NCCL_HW_NET ][ a ][ p ];
2019-11-19 14:57:39 -08:00
if ( a == NCCL_ALGO_RING ) {
float lat = hwLat [ hw [ a ]][ a ][ p ];
2020-09-04 14:35:05 -07:00
if (( coll == ncclFuncReduce || coll == ncclFuncBroadcast )) {
2019-11-19 14:57:39 -08:00
if ( ringGraph -> sameChannels ) {
comm -> latencies [ coll ][ a ][ p ] += lat ;
} else {
if ( p == NCCL_PROTO_SIMPLE ) lat = hwLat [ hw [ a ]][ NCCL_ALGO_TREE ][ p ]; // Add some chunk latency, waiting for proper chunk modeling
comm -> latencies [ coll ][ a ][ p ] += nsteps * lat ;
}
} else {
2020-05-12 14:40:18 -07:00
comm -> latencies [ coll ][ a ][ p ] += ( nsteps - nInterSteps ) * intraLat + nInterSteps * interLat ;
2019-11-19 14:57:39 -08:00
}
2020-01-16 16:02:42 -08:00
} else if ( a == NCCL_ALGO_TREE ) {
2019-11-19 14:57:39 -08:00
comm -> latencies [ coll ][ a ][ p ] +=
2020-09-04 14:35:05 -07:00
2 * (( nRanks / nNodes - 1 ) * intraLat + log2i ( nNodes ) * interLat );
2020-01-16 16:02:42 -08:00
} else {
comm -> latencies [ coll ][ a ][ p ] +=
2020-09-04 14:35:05 -07:00
2 * ( nRanks / nNodes - 1 ) * intraLat + interLat ;
2019-11-19 14:57:39 -08:00
}
}
}
}
// Protocols/Algorithms enable/disable, and user overrides.
// All are enabled except ll128 which is enabled by default only in certain cases.
int protoEnable [ NCCL_NUM_PROTOCOLS ] = { 1 , 2 , 1 };
2020-01-16 16:02:42 -08:00
int algoEnable [ NCCL_NUM_ALGORITHMS ] = { 1 , 1 , 1 };
2019-11-19 14:57:39 -08:00
const char * protoStr = getenv ( "NCCL_PROTO" );
2020-05-12 14:40:18 -07:00
if ( protoStr ) {
INFO ( NCCL_ENV , "NCCL_PROTO set by environment to %s" , protoStr );
NCCLCHECK ( parseList ( protoStr , ncclProtoStr , NCCL_NUM_PROTOCOLS , protoEnable ));
}
2019-11-19 14:57:39 -08:00
const char * algoStr = getenv ( "NCCL_ALGO" );
2020-05-12 14:40:18 -07:00
if ( algoStr ) {
INFO ( NCCL_ENV , "NCCL_ALGO set by environment to %s" , algoStr );
NCCLCHECK ( parseList ( algoStr , ncclAlgoStr , NCCL_NUM_ALGORITHMS , algoEnable ));
}
2020-09-04 14:35:05 -07:00
// Disable CollNet if it is not supported
if ( comm -> collNetSupport == 0 ) {
algoEnable [ NCCL_ALGO_COLLNET ] = 0 ;
// If user has hard set NCCL_ALGO=COLLNET, ignore it
if ( algoEnable [ NCCL_ALGO_RING ] == 0 && algoEnable [ NCCL_ALGO_TREE ] == 0 ) {
algoEnable [ NCCL_ALGO_RING ] = algoEnable [ NCCL_ALGO_TREE ] = 1 ;
if ( comm -> rank == 0 ) WARN ( "CollNet is not supported or fails to initialize, ignoring NCCL_ALGO=COLLNET" );
}
}
2019-11-19 14:57:39 -08:00
for ( int c = 0 ; c < NCCL_NUM_FUNCTIONS ; c ++ ) for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) for ( int p = 0 ; p < NCCL_NUM_PROTOCOLS ; p ++ ) {
int pEnable = protoEnable [ p ];
if ( pEnable == 2 && p == NCCL_PROTO_LL128 ) {
2020-05-12 14:40:18 -07:00
// Enable LL128 by default only on Volta/Ampere+NVLink. Other cases are not tested and may cause silent data corruption.
pEnable = ( graphs [ a ] -> typeInter <= PATH_PXB ) && graphs [ a ] -> typeIntra <= PATH_NVL &&
(( minCompCap == 70 && maxCompCap == 70 ) || ( minCompCap == 80 && maxCompCap == 80 )) ? 1 : 0 ;
2019-11-19 14:57:39 -08:00
}
2020-05-12 14:40:18 -07:00
if ( pEnable == 0 ) comm -> bandwidths [ c ][ a ][ p ] = 0 ;
// Only disable algo for Allreduce since others only have one
2020-09-04 14:35:05 -07:00
if ( c == ncclFuncAllReduce && algoEnable [ a ] == 0 ) comm -> bandwidths [ c ][ a ][ p ] = 0 ;
2019-11-19 14:57:39 -08:00
}
if ( comm -> rank == 0 ) {
char line [ 1024 ];
sprintf ( line , "Latency/AlgBw |" );
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) {
for ( int p = 0 ; p < NCCL_NUM_PROTOCOLS ; p ++ ) {
2020-01-16 16:02:42 -08:00
sprintf ( line + strlen ( line ), " %7s/%6s |" , ncclAlgoStr [ a ], ncclProtoStr [ p ]);
}
}
INFO ( NCCL_TUNING , "%s" , line );
sprintf ( line , " Max NThreads |" );
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) {
for ( int p = 0 ; p < NCCL_NUM_PROTOCOLS ; p ++ ) {
sprintf ( line + strlen ( line ), " %14d |" , comm -> maxThreads [ a ][ p ]);
2019-11-19 14:57:39 -08:00
}
}
INFO ( NCCL_TUNING , "%s" , line );
for ( int c = 0 ; c < NCCL_NUM_FUNCTIONS ; c ++ ) {
sprintf ( line , "%13s |" , ncclFuncStr [ c ]);
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) {
for ( int p = 0 ; p < NCCL_NUM_PROTOCOLS ; p ++ ) {
2020-01-16 16:02:42 -08:00
sprintf ( line + strlen ( line ), "%8.1f/%6.1f |" , comm -> latencies [ c ][ a ][ p ], comm -> bandwidths [ c ][ a ][ p ]);
2019-11-19 14:57:39 -08:00
}
}
INFO ( NCCL_TUNING , "%s" , line );
}
}
// Set per-thread amount of work before we increase nThreads and nChannels
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) {
comm -> threadThresholds [ a ][ NCCL_PROTO_LL ] = NCCL_LL_THREAD_THRESHOLD ;
comm -> threadThresholds [ a ][ NCCL_PROTO_LL128 ] = NCCL_LL128_THREAD_THRESHOLD ;
comm -> threadThresholds [ a ][ NCCL_PROTO_SIMPLE ] = NCCL_SIMPLE_THREAD_THRESHOLD ;
}
2020-09-04 14:35:05 -07:00
comm -> threadThresholds [ NCCL_ALGO_RING ][ NCCL_PROTO_LL ] *= nRanks ;
2019-11-19 14:57:39 -08:00
// Override defaults with user env
char * str = getenv ( "NCCL_THREAD_THRESHOLDS" );
if ( str ) {
2020-05-12 14:40:18 -07:00
INFO ( NCCL_ENV , "NCCL_THREAD_THRESHOLDS set by environment to %s" , str );
2019-12-06 09:55:54 -08:00
ssize_t t [ NCCL_NUM_ALGORITHMS ][ NCCL_NUM_PROTOCOLS ] = {{ - 2 , - 2 , - 2 }, { - 2 , - 2 , - 2 }};
2019-11-19 14:57:39 -08:00
sscanf ( str , "%ld %ld %ld %ld %ld %ld" , t [ 0 ], t [ 0 ] + 1 , t [ 0 ] + 2 , t [ 1 ], t [ 1 ] + 1 , t [ 1 ] + 2 );
for ( int a = 0 ; a < NCCL_NUM_ALGORITHMS ; a ++ ) {
for ( int p = 0 ; p < NCCL_NUM_PROTOCOLS ; p ++ ) {
if ( t [ a ][ p ] >= 0 ) comm -> threadThresholds [ a ][ p ] = t [ a ][ p ];
}
}
}
2020-01-16 16:02:42 -08:00
INFO ( NCCL_INIT , "threadThresholds %ld/%ld/%ld | %ld/%ld/%ld | %ld/%ld/%ld" ,
2019-11-19 14:57:39 -08:00
comm -> threadThresholds [ NCCL_ALGO_TREE ][ NCCL_PROTO_LL ],
comm -> threadThresholds [ NCCL_ALGO_TREE ][ NCCL_PROTO_LL128 ],
comm -> threadThresholds [ NCCL_ALGO_TREE ][ NCCL_PROTO_SIMPLE ],
comm -> threadThresholds [ NCCL_ALGO_RING ][ NCCL_PROTO_LL ],
comm -> threadThresholds [ NCCL_ALGO_RING ][ NCCL_PROTO_LL128 ],
2020-01-16 16:02:42 -08:00
comm -> threadThresholds [ NCCL_ALGO_RING ][ NCCL_PROTO_SIMPLE ],
comm -> threadThresholds [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_LL ],
comm -> threadThresholds [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_LL128 ],
comm -> threadThresholds [ NCCL_ALGO_COLLNET ][ NCCL_PROTO_SIMPLE ]);
return ncclSuccess ;
}
// Trees are not perfectly sticking to the model for medium sizes. Applying a static correction
2020-05-12 14:40:18 -07:00
// factor is not ideal but works quite well. Powers of two, 64 B to 128MB.
2020-01-16 16:02:42 -08:00
static float treeCorrectionFactor [ NCCL_NUM_PROTOCOLS ][ 22 ] = {
2020-04-01 13:21:38 -07:00
{ 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , .84 , .49 , .42 , .60 , .75 , .87 , .94 , .94 , .99 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 },
{ 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , .84 , .49 , .42 , .60 , .75 , .87 , .94 , .94 , .99 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 },
{ 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , .41 , .27 , .25 , .39 , .46 , .72 , .76 , .87 , .92 , .97 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 }
};
static float ringCorrectionFactor [ NCCL_NUM_PROTOCOLS ][ 22 ] = {
{ 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , .25 , .41 , .55 , .56 , .78 , .94 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 },
{ 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , .25 , .41 , .55 , .56 , .78 , .94 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 },
{ 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 , .04 , .08 , .09 , .09 , .11 , .13 , .25 , .40 , .59 , .76 , .86 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 }
2020-01-16 16:02:42 -08:00
};
ncclResult_t ncclTopoGetAlgoTime ( struct ncclInfo * info , int algorithm , int protocol , float * time ) {
float bw = info -> comm -> bandwidths [ info -> coll ][ algorithm ][ protocol ];
2020-05-12 14:40:18 -07:00
float lat = info -> comm -> latencies [ info -> coll ][ algorithm ][ protocol ];
2020-01-16 16:02:42 -08:00
if ( bw == 0 ) {
* time = - 1.0 ; return ncclSuccess ;
}
int logSize = log2i ( info -> nBytes >> 6 );
2020-12-01 11:33:47 -05:00
#if defined(__HIP_PLATFORM_HCC__) || defined(__HCC__) || defined(__HIPCC__)
2020-01-16 16:02:42 -08:00
if ( algorithm == NCCL_ALGO_TREE && logSize < 22 ) bw *= treeCorrectionFactor [ protocol ][ logSize ];
2020-04-01 13:21:38 -07:00
else if ( algorithm == NCCL_ALGO_RING && logSize < 22 ) bw *= ringCorrectionFactor [ protocol ][ logSize ];
2020-12-01 11:33:47 -05:00
#else
2020-09-04 14:35:05 -07:00
if ( algorithm == NCCL_ALGO_TREE && logSize < 23 ) bw *= treeCorrectionFactor [ protocol ][ logSize ];
if ( info -> nChannels != 0 ) bw = bw / info -> comm -> nChannels * info -> nChannels ;
2020-05-12 14:40:18 -07:00
if ( algorithm == NCCL_ALGO_RING && protocol == NCCL_PROTO_SIMPLE && info -> comm -> nNodes > 1
2020-09-04 14:35:05 -07:00
&& info -> coll == ncclFuncAllReduce && info -> nBytes >= info -> comm -> nRanks / 16.0 * 65536 ) lat *= 1.9 ; // Plateau effect of ring
2020-12-01 11:33:47 -05:00
#endif
2020-05-12 14:40:18 -07:00
* time = lat + ( info -> nBytes ) / ( 1000 * bw );
2019-11-19 14:57:39 -08:00
return ncclSuccess ;
}