diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b9e428..84847a37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ Documentation for TransferBench is available at ## v1.67.00 ### Added +- Added NIC_TRAFFIC_CLASS to set the DSCP/traffic class byte in the RoCE GRH for QPs (RoCE only) +- Added NIC_SERVICE_LEVEL to set the IB service level (sl) for QPs (IB and RoCE) - Initial support for pod communication. Requires compatible hardware / ROCm version and subject to further testing - This potentially enables GFX/DMA executors to access SRC/DST memory locations on GPUs within the same pod - Pod membership requires amd-smi however can be skipped by setting TB_FORCE_SINGLE_POD=1 diff --git a/src/client/EnvVars.hpp b/src/client/EnvVars.hpp index 27ef8849..34940b69 100644 --- a/src/client/EnvVars.hpp +++ b/src/client/EnvVars.hpp @@ -120,6 +120,8 @@ class EnvVars int nicChunkBytes; // Number of bytes to send per chunk for RDMA operations int nicCqPollBatch; // Number of CQ entries to poll per ibv_poll_cq call int nicRelaxedOrder; // Use relaxed ordering for RDMA + int nicServiceLevel; // IB service level (sl) for InfiniBand QPs + int nicTrafficClass; // DSCP/traffic class byte for RoCE GRH int roceVersion; // RoCE version number // Developer features @@ -185,6 +187,18 @@ class EnvVars nicChunkBytes = GetEnvVar("NIC_CHUNK_BYTES" , 1073741824); nicCqPollBatch = GetEnvVar("NIC_CQ_POLL_BATCH" , 4); nicRelaxedOrder = GetEnvVar("NIC_RELAX_ORDER" , 1); + nicServiceLevel = GetEnvVar("NIC_SERVICE_LEVEL" , 0); + nicTrafficClass = GetEnvVar("NIC_TRAFFIC_CLASS" , 0); + + // Check that NIC service level and traffic class are in valid ranges + if (nicServiceLevel < 0 || nicServiceLevel > 15) { + printf("[ERROR] NIC_SERVICE_LEVEL must be in range 0..15 (got %d)\n", nicServiceLevel); + exit(1); + } + if (nicTrafficClass < 0 || nicTrafficClass > 255) { + printf("[ERROR] NIC_TRAFFIC_CLASS must be in range 0..255 (got %d)\n", nicTrafficClass); + exit(1); + } gpuMaxHwQueues = GetEnvVar("GPU_MAX_HW_QUEUES" , 4); @@ -366,6 +380,8 @@ class EnvVars printf(" NIC_CHUNK_BYTES - Number of bytes to send at a time using NIC (default = 1GB)\n"); printf(" NIC_CQ_POLL_BATCH - Number of CQ entries to poll per ibv_poll_cq call (default = 4)\n"); printf(" NIC_RELAX_ORDER - Set to non-zero to use relaxed ordering\n"); + printf(" NIC_SERVICE_LEVEL - IB service level (sl) for InfiniBand QPs (default=0)\n"); + printf(" NIC_TRAFFIC_CLASS - DSCP/traffic class byte for RoCE GRH (default=0)\n"); #endif printf(" NUM_ITERATIONS - # of timed iterations per test. If negative, run for this many seconds instead\n"); printf(" NUM_SUBITERATIONS - # of sub-iterations to run per iteration. Must be non-negative\n"); @@ -504,6 +520,10 @@ class EnvVars "Polling %d CQ entries per ibv_poll_cq call", nicCqPollBatch); Print("NIC_RELAX_ORDER", nicRelaxedOrder, "Using %s ordering for NIC RDMA", nicRelaxedOrder ? "relaxed" : "strict"); + Print("NIC_SERVICE_LEVEL", nicServiceLevel, + "IB service level (sl) set to %d", nicServiceLevel); + Print("NIC_TRAFFIC_CLASS", nicTrafficClass, + "RoCE traffic class (DSCP) set to %d", nicTrafficClass); #endif Print("NUM_ITERATIONS", numIterations, (numIterations == 0) ? "Running infinitely" : @@ -725,6 +745,8 @@ class EnvVars cfg.nic.ibPort = ibPort; cfg.nic.ipAddressFamily = ipAddressFamily; cfg.nic.useRelaxedOrder = nicRelaxedOrder; + cfg.nic.serviceLevel = nicServiceLevel; + cfg.nic.trafficClass = nicTrafficClass; cfg.nic.roceVersion = roceVersion; return cfg; diff --git a/src/header/TransferBench.hpp b/src/header/TransferBench.hpp index 3ff0d276..d94eb725 100644 --- a/src/header/TransferBench.hpp +++ b/src/header/TransferBench.hpp @@ -270,6 +270,8 @@ namespace TransferBench int queueSize = 100; ///< Completion queue size int roceVersion = 2; ///< RoCE version (used for auto GID detection) int useRelaxedOrder = 1; ///< Use relaxed ordering + uint8_t serviceLevel = 0; ///< IB service level (sl) for InfiniBand QPs + uint8_t trafficClass = 0; ///< DSCP/traffic class byte for RoCE GRH int useNuma = 0; ///< Switch to closest numa thread for execution }; @@ -2000,6 +2002,8 @@ namespace { if (nic.maxSendWorkReq != cfg.nic.maxSendWorkReq) ADD_ERROR("cfg.nic.maxSendWorkReq"); // nic.queueSize is permitted to be different across ranks if (nic.roceVersion != cfg.nic.roceVersion) ADD_ERROR("cfg.nic.roceVersion"); + if (nic.serviceLevel != cfg.nic.serviceLevel) ADD_ERROR("cfg.nic.serviceLevel"); + if (nic.trafficClass != cfg.nic.trafficClass) ADD_ERROR("cfg.nic.trafficClass"); if (nic.useRelaxedOrder != cfg.nic.useRelaxedOrder) ADD_ERROR("cfg.nic.useRelaxedOrder"); if (nic.useNuma != cfg.nic.useNuma) ADD_ERROR("cfg.nic.useNuma"); } @@ -3284,7 +3288,9 @@ static bool IsConfiguredGid(union ibv_gid const& gid) ConnInfo const& connInfo, uint8_t const& port, bool const& isRoCE, - ibv_mtu const& mtu) + ibv_mtu const& mtu, + uint8_t const& trafficClass, + uint8_t const& serviceLevel) { // Prepare QP attributes struct ibv_qp_attr attr = {}; @@ -3300,11 +3306,12 @@ static bool IsConfiguredGid(union ibv_gid const& gid) attr.ah_attr.grh.flow_label = 0; attr.ah_attr.grh.sgid_index = connInfo.gidIdx; attr.ah_attr.grh.hop_limit = 255; + attr.ah_attr.grh.traffic_class = trafficClass; } else { attr.ah_attr.is_global = 0; attr.ah_attr.dlid = connInfo.lid; } - attr.ah_attr.sl = 0; + attr.ah_attr.sl = serviceLevel; attr.ah_attr.src_path_bits = 0; attr.ah_attr.port_num = port; attr.dest_qp_num = connInfo.qpn; @@ -3588,7 +3595,7 @@ static bool IsConfiguredGid(union ibv_gid const& gid) static_assert(std::is_trivially_copyable::value, "QpTransitionResult must be trivially copyable for MPI broadcast"); QpTransitionResult srcQpResult = {ERR_NONE, false}; if (GetRank() == srcMemRank) { - ErrResult err = TransitionQpToRtr(rss.srcQueuePairs[i], dstConnInfo, port, srcIsRoCE, rss.srcPortAttr.active_mtu); + ErrResult err = TransitionQpToRtr(rss.srcQueuePairs[i], dstConnInfo, port, srcIsRoCE, rss.srcPortAttr.active_mtu, cfg.nic.trafficClass, cfg.nic.serviceLevel); srcQpResult.rtrFailed = (err.errType != ERR_NONE); if (err.errType == ERR_NONE) { err = TransitionQpToRts(rss.srcQueuePairs[i]); @@ -3603,7 +3610,7 @@ static bool IsConfiguredGid(union ibv_gid const& gid) QpTransitionResult dstQpResult = {ERR_NONE, false}; if (GetRank() == dstMemRank) { - ErrResult err = TransitionQpToRtr(rss.dstQueuePairs[i], srcConnInfo, port, dstIsRoCE, rss.dstPortAttr.active_mtu); + ErrResult err = TransitionQpToRtr(rss.dstQueuePairs[i], srcConnInfo, port, dstIsRoCE, rss.dstPortAttr.active_mtu, cfg.nic.trafficClass, cfg.nic.serviceLevel); dstQpResult.rtrFailed = (err.errType != ERR_NONE); if (err.errType == ERR_NONE) { err = TransitionQpToRts(rss.dstQueuePairs[i]);