已合并
[feat] 支持通过环境变量配置多QP UDP源端口 #5135
[feat] 支持通过环境变量配置多QP UDP源端口 #5135
已合并
刘宏明创建于 9月8日
共 15 个文件变更+578-276
@@ -39,6 +39,7 @@
39#include "channel_config.h"39#include "channel_config.h"
40#include "hcclCommDfx.h"40#include "hcclCommDfx.h"
41#include "coll_comm_res_c_adpt.h"41#include "coll_comm_res_c_adpt.h"
42+#include "roce_channel_desc_configurator.h"
42#include "common/loggers/channel_logger.h"43#include "common/loggers/channel_logger.h"
43 44 
44using namespace hccl;45using namespace hccl;
@@ -76,7 +77,7 @@ static u32 ResolveQueueNum(const Hccl::EnvRdmaConfig& rdmaConfig, const HcclChan
76 if (channelDesc.channelProtocol == COMM_PROTOCOL_ROCE77 if (channelDesc.channelProtocol == COMM_PROTOCOL_ROCE
77 && channelDesc.localEndpoint.loc.locType == ENDPOINT_LOC_TYPE_HOST) {78 && channelDesc.localEndpoint.loc.locType == ENDPOINT_LOC_TYPE_HOST) {
78 u32 hostQpCount = 0;79 u32 hostQpCount = 0;
79- MyRankUtils::ReadHostNicMultiQpCount(hostQpCount);80+ RoceChannelDescConfigurator::ReadHostNicMultiQpCount(hostQpCount);
80 if (hostQpCount > 0) {81 if (hostQpCount > 0) {
81 return hostQpCount;82 return hostQpCount;
82 }83 }
@@ -10,6 +10,7 @@
10 10 
11set(src_list11set(src_list
12 my_rank.cc12 my_rank.cc
13+ roce_channel_desc_configurator.cc
13 exchange_info_mgr.cc14 exchange_info_mgr.cc
14 shared_jetty_channel_pool.cc15 shared_jetty_channel_pool.cc
15)16)
@@ -25,4 +26,4 @@ endif()
25 26 
26add_subdirectory(comm_mems)27add_subdirectory(comm_mems)
27add_subdirectory(comm_engine)28add_subdirectory(comm_engine)
28-add_subdirectory(endpoints)29+add_subdirectory(endpoints)
@@ -31,6 +31,7 @@
31#include "ccu_res.h"31#include "ccu_res.h"
32#include "coll_comm_mgr.h"32#include "coll_comm_mgr.h"
33#include "new_rank_info.h"33#include "new_rank_info.h"
34+#include "roce_channel_desc_configurator.h"
34 35 
35#include <acl/acl.h>36#include <acl/acl.h>
36#include <unordered_map>37#include <unordered_map>
@@ -109,215 +110,8 @@ inline const char* GetTlsStatusStr(Hccl::TlsStatus tlsStatus)
109 return "UNKNOWN";110 return "UNKNOWN";
110}111}
111 112 
112-bool ParseStrictDecimal(const std::string& value, uint32_t minValue, uint32_t maxValue, uint32_t& parsed)
113-{
114- const auto isDecimalDigit = [](unsigned char character) {
115- return std::isdigit(character) != 0;
116- };
117- const bool hasValidDecimalFormat = !value.empty() && std::all_of(value.begin(), value.end(), isDecimalDigit);
118- if (!hasValidDecimalFormat) {
119- HCCL_WARNING("[%s] value[%s] is not a valid decimal number", __func__, value.c_str());
120- return false;
121- }
122- 
123- errno = 0;
124- char* end = nullptr;
125- const unsigned long number = std::strtoul(value.c_str(), &end, 10);
126- if (errno == ERANGE || end != value.c_str() + value.size()) {
127- HCCL_WARNING("[%s] parse value[%s] failed", __func__, value.c_str());
128- return false;
129- }
130- if (number < minValue || number > maxValue) {
131- HCCL_WARNING("[%s] value[%s] is out of range[%u, %u]", __func__, value.c_str(), minValue, maxValue);
132- return false;
133- }
134- 
135- parsed = static_cast<uint32_t>(number);
136- return true;
137-}
138- 
139-bool ParseMultiQpUdpPorts(const std::string& value, std::vector<std::uint16_t>& ports)
140-{
141- if (value.empty()) {
142- HCCL_WARNING("[%s] ports config is empty", __func__);
143- return false;
144- }
145- 
146- std::vector<std::uint16_t> parsedPorts;
147- std::size_t start = 0;
148- while (start <= value.size()) {
149- const std::size_t comma = value.find(',', start);
150- const std::string token = value.substr(start, comma == std::string::npos ? std::string::npos : comma - start);
151- uint32_t port = 0;
152- if (!ParseStrictDecimal(token, 1, Hccl::MultiQpSrcPortConfig::CONFIG_SRC_PORT_ID_MAX, port)) {
153- HCCL_WARNING("[%s] invalid port[%s]", __func__, token.c_str());
154- return false;
155- }
156- parsedPorts.emplace_back(static_cast<std::uint16_t>(port));
157- if (parsedPorts.size() > Hccl::MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX) {
158- HCCL_WARNING(
159- "[%s] ports count[%zu] exceeds the maximum[%u]", __func__, parsedPorts.size(),
160- Hccl::MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX);
161- return false;
162- }
163- if (comma == std::string::npos) {
164- break;
165- }
166- start = comma + 1;
167- }
168- 
169- ports = std::move(parsedPorts);
170- return true;
171-}
172- 
173-bool ReadHostConfigValue(RaInfo& info, HccnCfgKey key, std::string& value)
174-{
175- std::vector<char> buffer(HOST_NIC_CONFIG_BUFFER_SIZE, '\0');
176- uint32_t valueLen = static_cast<uint32_t>(buffer.size());
177- const int ret = RaGetHccnCfg(&info, key, buffer.data(), &valueLen);
178- // 配置文件不存在或配置项为空时,RaGetHccnCfg返回成功和空值,不会进入该分支
179- if (ret != 0) {
180- HCCL_WARNING("[%s] RaGetHccnCfg failed, phyId[%u], key[%d], ret[%d]", __func__, info.phyId, key, ret);
181- return false;
182- }
183- 
184- valueLen = std::min<uint32_t>(valueLen, static_cast<uint32_t>(buffer.size()));
185- value.assign(buffer.data(), valueLen);
186- if (!value.empty() && value.back() == '\0') {
187- value.pop_back();
188- }
189- return true;
190-}
191- 
192-static bool
193-ReadHostNicMultiQpConfigItem(uint32_t devicePhyId, HccnCfgKey key, const char* itemName, std::string& itemValue)
194-{
195- RaInfo info{};
196- info.mode = NETWORK_PEER_ONLINE;
197- info.phyId = devicePhyId;
198- std::string mode;
199- if (!ReadHostConfigValue(info, HCCN_CFG_UDP_PORT_MODE, mode)) {
200- return false;
201- }
202- if (mode.empty()) {
203- HCCL_WARNING("[%s] no host multi-qp config, phyId[%u]", __func__, devicePhyId);
204- return false;
205- }
206- if (mode != "multi_qp") {
207- HCCL_WARNING("[%s] invalid udp_port_mode[%s], phyId[%u]", __func__, mode.c_str(), devicePhyId);
208- return false;
209- }
210- 
211- if (!ReadHostConfigValue(info, key, itemValue)) {
212- return false;
213- }
214- if (itemValue.empty()) {
215- HCCL_WARNING("[%s] incomplete host multi-qp config, phyId[%u] %s[0]", __func__, devicePhyId, itemName);
216- return false;
217- }
218- return true;
219-}
220- 
221-void ReadHostNicMultiQpCount(uint32_t& qpCount)
222-{
223- qpCount = 0;
224- s32 deviceLogicId = INVALID_INT;
225- uint32_t devicePhyId = INVALID_UINT;
226- if ((hrtGetDevice(&deviceLogicId) != HCCL_SUCCESS)
227- || (hrtGetDevicePhyIdByIndex(static_cast<uint32_t>(deviceLogicId), devicePhyId, false) != HCCL_SUCCESS)) {
228- return;
229- }
230- 
231- std::string count;
232- if (!ReadHostNicMultiQpConfigItem(devicePhyId, HCCN_CFG_MULTI_QP_COUNT, "multi_qp_count", count)) {
233- return;
234- }
235- 
236- uint32_t parsedQpCount = 0;
237- if (!ParseStrictDecimal(count, 1, Hccl::MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX, parsedQpCount)) {
238- HCCL_WARNING("[%s] invalid multi_qp_count[%s], phyId[%u]", __func__, count.c_str(), devicePhyId);
239- return;
240- }
241- 
242- qpCount = parsedQpCount;
243- HCCL_INFO("[%s] host config valid, phyId[%u] count[%u]", __func__, devicePhyId, qpCount);
244-}
245- 
246-void ReadHostNicMultiQpUdpPorts(std::vector<std::uint16_t>& qpUdpPorts)
247-{
248- qpUdpPorts.clear();
249- s32 deviceLogicId = INVALID_INT;
250- uint32_t devicePhyId = INVALID_UINT;
251- if ((hrtGetDevice(&deviceLogicId) != HCCL_SUCCESS)
252- || (hrtGetDevicePhyIdByIndex(static_cast<uint32_t>(deviceLogicId), devicePhyId, false) != HCCL_SUCCESS)) {
253- return;
254- }
255- 
256- std::string ports;
257- if (!ReadHostNicMultiQpConfigItem(devicePhyId, HCCN_CFG_MULTI_QP_UDP_PORTS, "multi_qp_udp_ports", ports)) {
258- return;
259- }
260- 
261- std::vector<std::uint16_t> parsedQpUdpPorts;
262- if (!ParseMultiQpUdpPorts(ports, parsedQpUdpPorts)) {
263- HCCL_WARNING("[%s] invalid multi_qp_udp_ports[%s], phyId[%u]", __func__, ports.c_str(), devicePhyId);
264- return;
265- }
266- 
267- qpUdpPorts = std::move(parsedQpUdpPorts);
268- HCCL_INFO("[%s] host config valid, phyId[%u] ports[%zu]", __func__, devicePhyId, qpUdpPorts.size());
269-}
270- 
271} // namespace MyRankUtils113} // namespace MyRankUtils
272 114 
273-HcclResult MyRankUtils::FillRoceSrcPortList(
274- const HcclChannelDesc& hcclDesc, HcommChannelDesc& hcommDesc, std::vector<uint16_t>& srcPortBuf)
275-{
276- hcommDesc.roceAttr.srcPortList = nullptr;
277- if (hcommDesc.remoteEndpoint.protocol != COMM_PROTOCOL_ROCE || hcommDesc.exchangeAllMems) {
278- HCCL_INFO(
279- "[%s] skip: protocol[%d] exchangeAllMems[%d]", __func__, hcommDesc.remoteEndpoint.protocol,
280- hcommDesc.exchangeAllMems);
281- return HCCL_SUCCESS;
282- }
283- 
284- std::vector<std::uint16_t> ports;
285- ReadHostNicMultiQpUdpPorts(ports);
286- if (ports.empty()) {
287- const auto& qpSrcPortConfig = Hccl::EnvConfig::GetInstance().GetRdmaConfig().GetMultiQpSrcPortConfig();
288- if (!qpSrcPortConfig.IsAvailable()) {
289- HCCL_INFO(
290- "[%s] skip: multiQpSrcPortConfig not available (env HCCL_RDMA_QP_PORT_CONFIG_PATH unset or "
291- "MultiQpSrcPort.cfg empty)",
292- __func__);
293- return HCCL_SUCCESS;
294- }
295- Hccl::IpAddress localIp;
296- Hccl::IpAddress remoteIp;
297- HcclResult localRet = CommAddrToIpAddress(hcclDesc.localEndpoint.commAddr, localIp);
298- HcclResult remoteRet = CommAddrToIpAddress(hcclDesc.remoteEndpoint.commAddr, remoteIp);
299- CHK_PRT_RET(
300- localRet != HCCL_SUCCESS || remoteRet != HCCL_SUCCESS,
301- HCCL_ERROR("[%s] CommAddrToIpAddress failed: localRet[%d] remoteRet[%d]", __func__, localRet, remoteRet),
302- HCCL_E_INTERNAL);
303- ports = Hccl::GetMultiQpSrcPortsByIpPair(qpSrcPortConfig, localIp, remoteIp);
304- if (ports.empty()) {
305- HCCL_INFO(
306- "[%s] skip: no matching ports for localIp[%s] remoteIp[%s]", __func__, localIp.GetIpStr().c_str(),
307- remoteIp.GetIpStr().c_str());
308- return HCCL_SUCCESS;
309- }
310- }
311- u32 queueNum = hcommDesc.roceAttr.queueNum;
312- srcPortBuf.resize(queueNum);
313- for (u32 j = 0; j < queueNum; ++j) {
314- srcPortBuf[j] = ports[j % ports.size()];
315- }
316- hcommDesc.roceAttr.srcPortList = srcPortBuf.data();
317- HCCL_INFO("[%s] success: queueNum[%u] portCount[%zu]", __func__, queueNum, ports.size());
318- return HCCL_SUCCESS;
319-}
320- 
321namespace hccl {115namespace hccl {
322 116 
323constexpr uint32_t UNREUSE_CHANNEL_IDX = 0xFFFFFFFF;117constexpr uint32_t UNREUSE_CHANNEL_IDX = 0xFFFFFFFF;
@@ -1452,15 +1246,12 @@ HcclResult MyRank::CreateChannels(
1452 auto& rdmaConfig = Hccl::EnvConfig::GetInstance().GetRdmaConfig();1246 auto& rdmaConfig = Hccl::EnvConfig::GetInstance().GetRdmaConfig();
1453 std::vector<HcommChannelDesc> hcommDescs(channelNum);1247 std::vector<HcommChannelDesc> hcommDescs(channelNum);
1454 std::vector<std::vector<MemHandle>> allHandles(channelNum);1248 std::vector<std::vector<MemHandle>> allHandles(channelNum);
1455- // srcPortBuffers 作为 hcommDescs[i].roceAttr.srcPortList 的底层 buffer,由 FillRoceSrcPortList 填充;1249+ RoceChannelDescConfigurator roceDescConfigurator(channelNum);
1456- // 生命周期需覆盖到通道构造完成(HostCpuRoceChannel 构造时深拷贝到自身 srcPortBuf_)。
1457- std::vector<std::vector<uint16_t>> srcPortBuffers(channelNum);
1458 for (u32 i = 0; i < channelNum; ++i) {1250 for (u32 i = 0; i < channelNum; ++i) {
1459 hcommDescs[i] = MyRankUtils::ChannelDescHccl2Hcomm(channelDescs[i], config_);1251 hcommDescs[i] = MyRankUtils::ChannelDescHccl2Hcomm(channelDescs[i], config_);
1460 hcommDescs[i].roceAttr.qpThreshold = rdmaConfig.GetRdmaMultiQpThreshold();1252 hcommDescs[i].roceAttr.qpThreshold = rdmaConfig.GetRdmaMultiQpThreshold();
1461 CHK_RET(ConfigSqDepthByExpansionMode(engine, hcommDescs[i]));1253 CHK_RET(ConfigSqDepthByExpansionMode(engine, hcommDescs[i]));
1462- 1254+ CHK_RET(roceDescConfigurator.FillRoceSrcPortList(channelDescs[i], i, hcommDescs[i]));
1463- CHK_RET(MyRankUtils::FillRoceSrcPortList(channelDescs[i], hcommDescs[i], srcPortBuffers[i]));
1464 }1255 }
1465 1256 
1466 auto start = std::chrono::steady_clock::now();1257 auto start = std::chrono::steady_clock::now();
@@ -0,0 +1,261 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "roce_channel_desc_configurator.h"
12+ 
13+#include "adapter_rts_common.h"
14+#include "env_config/env_config_v2.h"
15+#include "hcomm_adapter_hccp.h"
16+#include "orion_adpt_utils.h"
17+ 
18+static bool ReadHostConfigValue(RaInfo& info, HccnCfgKey key, std::string& value)
19+{
20+ std::vector<char> buffer(hccl::RoceChannelDescConfigurator::HOST_NIC_CONFIG_BUFFER_SIZE, '\0');
21+ uint32_t valueLen = static_cast<uint32_t>(buffer.size());
22+ const int ret = RaGetHccnCfg(&info, key, buffer.data(), &valueLen);
23+ // 配置文件不存在或配置项为空时,RaGetHccnCfg返回成功和空值,不会进入该分支
24+ if (ret != 0) {
25+ HCCL_WARNING("[%s] RaGetHccnCfg failed, phyId[%u], key[%d], ret[%d]", __func__, info.phyId, key, ret);
26+ return false;
27+ }
28+ 
29+ valueLen = std::min<uint32_t>(valueLen, static_cast<uint32_t>(buffer.size()));
30+ value.assign(buffer.data(), valueLen);
31+ if (!value.empty() && value.back() == '\0') {
32+ value.pop_back();
33+ }
34+ return true;
35+}
36+ 
37+static bool
38+ReadHostNicMultiQpConfigItem(uint32_t devicePhyId, HccnCfgKey key, const char* itemName, std::string& itemValue)
39+{
40+ RaInfo info{};
41+ info.mode = NETWORK_PEER_ONLINE;
42+ info.phyId = devicePhyId;
43+ std::string mode;
44+ if (!ReadHostConfigValue(info, HCCN_CFG_UDP_PORT_MODE, mode)) {
45+ return false;
46+ }
47+ if (mode.empty()) {
48+ HCCL_WARNING("[%s] no host multi-qp config, phyId[%u]", __func__, devicePhyId);
49+ return false;
50+ }
51+ if (mode != "multi_qp") {
52+ HCCL_WARNING("[%s] invalid udp_port_mode[%s], phyId[%u]", __func__, mode.c_str(), devicePhyId);
53+ return false;
54+ }
55+ 
56+ if (!ReadHostConfigValue(info, key, itemValue)) {
57+ return false;
58+ }
59+ if (itemValue.empty()) {
60+ HCCL_WARNING("[%s] incomplete host multi-qp config, phyId[%u] %s[0]", __func__, devicePhyId, itemName);
61+ return false;
62+ }
63+ return true;
64+}
65+ 
66+namespace hccl {
67+ 
68+constexpr std::size_t RoceChannelDescConfigurator::HOST_NIC_CONFIG_BUFFER_SIZE;
69+ 
70+RoceChannelDescConfigurator::RoceChannelDescConfigurator(uint32_t channelNum) : srcPortBuffers_(channelNum) {}
71+ 
72+bool RoceChannelDescConfigurator::ParseStrictDecimal(
73+ const std::string& value, uint32_t minValue, uint32_t maxValue, uint32_t& parsed)
74+{
75+ const auto isDecimalDigit = [](unsigned char character) {
76+ return std::isdigit(character) != 0;
77+ };
78+ const bool hasValidDecimalFormat = !value.empty() && std::all_of(value.begin(), value.end(), isDecimalDigit);
79+ if (!hasValidDecimalFormat) {
80+ HCCL_WARNING("[%s] value[%s] is not a valid decimal number", __func__, value.c_str());
81+ return false;
82+ }
83+ 
84+ errno = 0;
85+ char* end = nullptr;
86+ const unsigned long number = std::strtoul(value.c_str(), &end, 10);
87+ if (errno == ERANGE || end != value.c_str() + value.size()) {
88+ HCCL_WARNING("[%s] parse value[%s] failed", __func__, value.c_str());
89+ return false;
90+ }
91+ if (number < minValue || number > maxValue) {
92+ HCCL_WARNING("[%s] value[%s] is out of range[%u, %u]", __func__, value.c_str(), minValue, maxValue);
93+ return false;
94+ }
95+ 
96+ parsed = static_cast<uint32_t>(number);
97+ return true;
98+}
99+ 
100+void RoceChannelDescConfigurator::ReadHostNicMultiQpCount(uint32_t& qpCount)
101+{
102+ qpCount = 0;
103+ s32 deviceLogicId = INVALID_INT;
104+ uint32_t devicePhyId = INVALID_UINT;
105+ if ((hrtGetDevice(&deviceLogicId) != HCCL_SUCCESS)
106+ || (hrtGetDevicePhyIdByIndex(static_cast<uint32_t>(deviceLogicId), devicePhyId, false) != HCCL_SUCCESS)) {
107+ return;
108+ }
109+ 
110+ std::string count;
111+ if (!ReadHostNicMultiQpConfigItem(devicePhyId, HCCN_CFG_MULTI_QP_COUNT, "multi_qp_count", count)) {
112+ return;
113+ }
114+ 
115+ uint32_t parsedQpCount = 0;
116+ if (!ParseStrictDecimal(count, 1, Hccl::MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX, parsedQpCount)) {
117+ HCCL_WARNING("[%s] invalid multi_qp_count[%s], phyId[%u]", __func__, count.c_str(), devicePhyId);
118+ return;
119+ }
120+ 
121+ qpCount = parsedQpCount;
122+ HCCL_INFO("[%s] host config valid, phyId[%u] count[%u]", __func__, devicePhyId, qpCount);
123+}
124+ 
125+void RoceChannelDescConfigurator::ReadHostNicMultiQpUdpPorts(std::vector<uint16_t>& qpUdpPorts)
126+{
127+ qpUdpPorts.clear();
128+ s32 deviceLogicId = INVALID_INT;
129+ uint32_t devicePhyId = INVALID_UINT;
130+ if ((hrtGetDevice(&deviceLogicId) != HCCL_SUCCESS)
131+ || (hrtGetDevicePhyIdByIndex(static_cast<uint32_t>(deviceLogicId), devicePhyId, false) != HCCL_SUCCESS)) {
132+ return;
133+ }
134+ 
135+ std::string ports;
136+ if (!ReadHostNicMultiQpConfigItem(devicePhyId, HCCN_CFG_MULTI_QP_UDP_PORTS, "multi_qp_udp_ports", ports)) {
137+ return;
138+ }
139+ 
140+ std::vector<uint16_t> parsedQpUdpPorts;
141+ if (!Hccl::ParseHostRdmaUdpPorts(ports, parsedQpUdpPorts)) {
142+ HCCL_WARNING("[%s] invalid multi_qp_udp_ports[%s], phyId[%u]", __func__, ports.c_str(), devicePhyId);
143+ return;
144+ }
145+ 
146+ qpUdpPorts = std::move(parsedQpUdpPorts);
147+ HCCL_INFO("[%s] host config valid, phyId[%u] ports[%zu]", __func__, devicePhyId, qpUdpPorts.size());
148+}
149+ 
150+void RoceChannelDescConfigurator::FillPortsFromHostRdmaUdpPortsList(std::vector<uint16_t>& ports)
151+{
152+ const auto& udpPortsList = Hccl::EnvConfig::GetInstance().GetRdmaConfig().GetHostRdmaUdpPortsList();
153+ if (!udpPortsList.IsAvailable()) {
154+ HCCL_INFO(
155+ "[%s] hostRdmaUdpPortsList not available (env HCCL_HOST_RDMA_UDP_PORTS_LIST unset or empty)", __func__);
156+ return;
157+ }
158+ 
159+ s32 deviceLogicId = INVALID_INT;
160+ uint32_t devicePhyId = INVALID_UINT;
161+ if ((hrtGetDevice(&deviceLogicId) != HCCL_SUCCESS)
162+ || (hrtGetDevicePhyIdByIndex(static_cast<uint32_t>(deviceLogicId), devicePhyId, false) != HCCL_SUCCESS)) {
163+ HCCL_WARNING("[%s] hrtGetDevice or hrtGetDevicePhyIdByIndex failed, fall back to MultiQpSrcPort.cfg", __func__);
164+ return;
165+ }
166+ 
167+ const auto portIter = udpPortsList.portsByPhyId.find(devicePhyId);
168+ if (portIter != udpPortsList.portsByPhyId.end()) {
169+ ports = portIter->second;
170+ }
171+ if (ports.empty()) {
172+ HCCL_INFO("[%s] no matching HCCL_HOST_RDMA_UDP_PORTS_LIST ports for phyId[%u]", __func__, devicePhyId);
173+ }
174+}
175+ 
176+HcclResult RoceChannelDescConfigurator::FillPortsFromMultiQpSrcPortConfig(
177+ const HcclChannelDesc& hcclDesc, std::vector<uint16_t>& ports)
178+{
179+ const auto& qpSrcPortConfig = Hccl::EnvConfig::GetInstance().GetRdmaConfig().GetMultiQpSrcPortConfig();
180+ if (!qpSrcPortConfig.IsAvailable()) {
181+ HCCL_INFO(
182+ "[%s] skip: multiQpSrcPortConfig not available (env HCCL_RDMA_QP_PORT_CONFIG_PATH unset or "
183+ "MultiQpSrcPort.cfg empty)",
184+ __func__);
185+ return HCCL_SUCCESS;
186+ }
187+ 
188+ Hccl::IpAddress localIp;
189+ Hccl::IpAddress remoteIp;
190+ HcclResult localRet = hcomm::CommAddrToIpAddress(hcclDesc.localEndpoint.commAddr, localIp);
191+ HcclResult remoteRet = hcomm::CommAddrToIpAddress(hcclDesc.remoteEndpoint.commAddr, remoteIp);
192+ CHK_PRT_RET(
193+ localRet != HCCL_SUCCESS || remoteRet != HCCL_SUCCESS,
194+ HCCL_ERROR("[%s] CommAddrToIpAddress failed: localRet[%d] remoteRet[%d]", __func__, localRet, remoteRet),
195+ HCCL_E_INTERNAL);
196+ ports = Hccl::GetMultiQpSrcPortsByIpPair(qpSrcPortConfig, localIp, remoteIp);
197+ if (ports.empty()) {
198+ HCCL_INFO(
199+ "[%s] skip: no matching ports for localIp[%s] remoteIp[%s]", __func__, localIp.GetIpStr().c_str(),
200+ remoteIp.GetIpStr().c_str());
201+ }
202+ return HCCL_SUCCESS;
203+}
204+ 
205+HcclResult
206+RoceChannelDescConfigurator::ResolveRoceSrcPorts(const HcclChannelDesc& hcclDesc, std::vector<uint16_t>& ports)
207+{
208+ ports.clear();
209+ ReadHostNicMultiQpUdpPorts(ports);
210+ if (!ports.empty()) {
211+ return HCCL_SUCCESS;
212+ }
213+ 
214+ FillPortsFromHostRdmaUdpPortsList(ports);
215+ if (!ports.empty()) {
216+ return HCCL_SUCCESS;
217+ }
218+ 
219+ return FillPortsFromMultiQpSrcPortConfig(hcclDesc, ports);
220+}
221+ 
222+HcclResult RoceChannelDescConfigurator::FillRoceSrcPortList(
223+ const HcclChannelDesc& hcclDesc, uint32_t channelIndex, HcommChannelDesc& hcommDesc)
224+{
225+ hcommDesc.roceAttr.srcPortList = nullptr;
226+ if (hcclDesc.localEndpoint.loc.locType != ENDPOINT_LOC_TYPE_HOST
227+ || hcommDesc.remoteEndpoint.protocol != COMM_PROTOCOL_ROCE || hcommDesc.exchangeAllMems) {
228+ HCCL_INFO(
229+ "[%s] skip: localLocType[%d] protocol[%d] exchangeAllMems[%d]", __func__,
230+ hcclDesc.localEndpoint.loc.locType, hcommDesc.remoteEndpoint.protocol, hcommDesc.exchangeAllMems);
231+ return HCCL_SUCCESS;
232+ }
233+ CHK_PRT_RET(
234+ channelIndex >= srcPortBuffers_.size(),
235+ HCCL_ERROR(
236+ "[%s] channelIndex[%u] is out of range, channelNum[%zu]", __func__, channelIndex, srcPortBuffers_.size()),
237+ HCCL_E_PARA);
238+ 
239+ std::vector<uint16_t> ports;
240+ CHK_RET(ResolveRoceSrcPorts(hcclDesc, ports));
241+ if (ports.empty()) {
242+ return HCCL_SUCCESS;
243+ }
244+ const uint32_t queueNum = hcommDesc.roceAttr.queueNum;
245+ if (ports.size() != static_cast<std::size_t>(queueNum)) {
246+ HCCL_RUN_WARNING(
247+ "[%s] UDP source port count[%zu] does not match queueNum[%u], ports will be truncated or reused "
248+ "cyclically",
249+ __func__, ports.size(), queueNum);
250+ }
251+ auto& srcPortBuffer = srcPortBuffers_[channelIndex];
252+ srcPortBuffer.resize(queueNum);
253+ for (uint32_t index = 0; index < queueNum; ++index) {
254+ srcPortBuffer[index] = ports[index % ports.size()];
255+ }
256+ hcommDesc.roceAttr.srcPortList = srcPortBuffer.data();
257+ HCCL_INFO("[%s] success: queueNum[%u] portCount[%zu]", __func__, queueNum, ports.size());
258+ return HCCL_SUCCESS;
259+}
260+ 
261+} // namespace hccl
@@ -0,0 +1,55 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#ifndef ROCE_CHANNEL_DESC_CONFIGURATOR_H
12+#define ROCE_CHANNEL_DESC_CONFIGURATOR_H
13+ 
14+#include <string>
15+#include <vector>
16+ 
17+#include "hccl/hccl_channel.h"
18+ 
19+namespace hccl {
20+ 
21+/**
22+ * @brief Prepares RoCE-specific parameters in HcommChannelDesc.
23+ *
24+ * The configurator owns the buffers referenced by HcommChannelDesc::roceAttr.srcPortList. Its lifetime must cover
25+ * channel creation so that the descriptors always reference valid storage.
26+ */
27+class RoceChannelDescConfigurator {
28+public:
29+ static constexpr std::size_t HOST_NIC_CONFIG_BUFFER_SIZE = 2048;
30+ 
31+ explicit RoceChannelDescConfigurator(uint32_t channelNum);
32+ RoceChannelDescConfigurator(const RoceChannelDescConfigurator&) = delete;
33+ RoceChannelDescConfigurator& operator=(const RoceChannelDescConfigurator&) = delete;
34+ RoceChannelDescConfigurator(RoceChannelDescConfigurator&&) = delete;
35+ RoceChannelDescConfigurator& operator=(RoceChannelDescConfigurator&&) = delete;
36+ 
37+ // 配置 RoCE 源端口,并保证 srcPortList 指向的内存在通道创建期间有效。
38+ HcclResult FillRoceSrcPortList(const HcclChannelDesc& hcclDesc, uint32_t channelIndex, HcommChannelDesc& hcommDesc);
39+ 
40+ // 读取并校验 Host 网卡的多 QP 数量。
41+ static void ReadHostNicMultiQpCount(uint32_t& qpCount);
42+ 
43+private:
44+ static bool ParseStrictDecimal(const std::string& value, uint32_t minValue, uint32_t maxValue, uint32_t& parsed);
45+ static void ReadHostNicMultiQpUdpPorts(std::vector<uint16_t>& qpUdpPorts);
46+ static void FillPortsFromHostRdmaUdpPortsList(std::vector<uint16_t>& ports);
47+ static HcclResult FillPortsFromMultiQpSrcPortConfig(const HcclChannelDesc& hcclDesc, std::vector<uint16_t>& ports);
48+ static HcclResult ResolveRoceSrcPorts(const HcclChannelDesc& hcclDesc, std::vector<uint16_t>& ports);
49+ 
50+ std::vector<std::vector<uint16_t>> srcPortBuffers_;
51+};
52+ 
53+} // namespace hccl
54+ 
55+#endif // ROCE_CHANNEL_DESC_CONFIGURATOR_H
@@ -133,6 +133,11 @@ void EnvRdmaConfig::Parse()
133 "[HCCL_ENV] HCCL_MULTI_QP_THRESHOLD set by %s to [%u]B", multiQpThreshold.GetSource(),133 "[HCCL_ENV] HCCL_MULTI_QP_THRESHOLD set by %s to [%u]B", multiQpThreshold.GetSource(),
134 GetRdmaMultiQpThreshold());134 GetRdmaMultiQpThreshold());
135 135 
136+ hostRdmaUdpPortsList.Parse();
137+ HCCL_RUN_INFO(
138+ "[HCCL_ENV] HCCL_HOST_RDMA_UDP_PORTS_LIST set by %s, device config count[%zu]",
139+ hostRdmaUdpPortsList.GetSource(), GetHostRdmaUdpPortsList().GetDeviceConfigCount());
140+ 
136 qpPortConfigPath.Parse();141 qpPortConfigPath.Parse();
137 HCCL_RUN_INFO(142 HCCL_RUN_INFO(
138 "[HCCL_ENV] HCCL_RDMA_QP_PORT_CONFIG_PATH set by %s to [%s]", qpPortConfigPath.GetSource(),143 "[HCCL_ENV] HCCL_RDMA_QP_PORT_CONFIG_PATH set by %s to [%s]", qpPortConfigPath.GetSource(),
@@ -363,6 +368,8 @@ u32 EnvRdmaConfig::GetRdmaQueueNum() const { return queueNum.Get(); }
363 368 
364u32 EnvRdmaConfig::GetRdmaMultiQpThreshold() const { return multiQpThreshold.Get(); }369u32 EnvRdmaConfig::GetRdmaMultiQpThreshold() const { return multiQpThreshold.Get(); }
365 370 
371+const HostRdmaUdpPortsList& EnvRdmaConfig::GetHostRdmaUdpPortsList() const { return hostRdmaUdpPortsList.Get(); }
372+ 
366const MultiQpSrcPortConfig& EnvRdmaConfig::GetMultiQpSrcPortConfig() const { return multiQpSrcPortConfig_; }373const MultiQpSrcPortConfig& EnvRdmaConfig::GetMultiQpSrcPortConfig() const { return multiQpSrcPortConfig_; }
367 374 
368// EnvUbConfig375// EnvUbConfig
@@ -126,6 +126,7 @@ public:
126 u32 GetRdmaRetryCnt() const;126 u32 GetRdmaRetryCnt() const;
127 u32 GetRdmaQueueNum() const;127 u32 GetRdmaQueueNum() const;
128 u32 GetRdmaMultiQpThreshold() const;128 u32 GetRdmaMultiQpThreshold() const;
129+ const HostRdmaUdpPortsList& GetHostRdmaUdpPortsList() const;
129 const MultiQpSrcPortConfig& GetMultiQpSrcPortConfig() const;130 const MultiQpSrcPortConfig& GetMultiQpSrcPortConfig() const;
130 131 
131 static constexpr u32 HCCL_RDMA_TC_DEFAULT = 132; // 默认的traffic class为132(33*4)132 static constexpr u32 HCCL_RDMA_TC_DEFAULT = 132; // 默认的traffic class为132(33*4)
@@ -168,6 +169,7 @@ private:
168 CfgField<std::string> qpPortConfigPath{169 CfgField<std::string> qpPortConfigPath{
169 "HCCL_RDMA_QP_PORT_CONFIG_PATH", "", Str2T<std::string>, CheckFilePath, SetRealPath};170 "HCCL_RDMA_QP_PORT_CONFIG_PATH", "", Str2T<std::string>, CheckFilePath, SetRealPath};
170 MultiQpSrcPortConfig multiQpSrcPortConfig_;171 MultiQpSrcPortConfig multiQpSrcPortConfig_;
172+ CfgField<HostRdmaUdpPortsList> hostRdmaUdpPortsList{"HCCL_HOST_RDMA_UDP_PORTS_LIST", {}, CastHostRdmaUdpPortsList};
171};173};
172 174 
173// UB配置175// UB配置
@@ -16,8 +16,8 @@
16#include <algorithm>16#include <algorithm>
17#include <sstream>17#include <sstream>
18#include <array>18#include <array>
19+#include <limits>
19 20 
20-#include "sal.h"
21#include "string_util.h"21#include "string_util.h"
22#include "base_config_legacy.h"22#include "base_config_legacy.h"
23#include "orion_adapter_rts.h"23#include "orion_adapter_rts.h"
@@ -26,8 +26,107 @@
26 26 
27namespace Hccl {27namespace Hccl {
28 28 
29+static bool ParseDecimalU32(const std::string& value, u32& parsed)
30+{
31+ if (value.empty() || !std::all_of(value.begin(), value.end(), [](unsigned char ch) {
32+ return std::isdigit(ch) != 0;
33+ })) {
34+ return false;
35+ }
36+ 
37+ errno = 0;
38+ char* end = nullptr;
39+ const unsigned long number = std::strtoul(value.c_str(), &end, 10);
40+ if (errno == ERANGE || end != value.c_str() + value.size() || number > std::numeric_limits<u32>::max()) {
41+ return false;
42+ }
43+ parsed = static_cast<u32>(number);
44+ return true;
45+}
46+ 
47+bool ParseHostRdmaUdpPorts(const std::string& value, std::vector<std::uint16_t>& ports)
48+{
49+ if (value.empty() || value.back() == ',') {
50+ HCCL_ERROR("[ParseHostRdmaUdpPorts] UDP source port list is empty or ends with a comma.");
51+ return false;
52+ }
53+ 
54+ std::vector<std::uint16_t> parsedPorts;
55+ size_t start = 0;
56+ while (true) {
57+ const size_t comma = value.find(',', start);
58+ const std::string token = value.substr(start, comma == std::string::npos ? std::string::npos : comma - start);
59+ u32 port = 0;
60+ if (!ParseDecimalU32(token, port) || port == 0 || port > MultiQpSrcPortConfig::CONFIG_SRC_PORT_ID_MAX) {
61+ HCCL_ERROR(
62+ "[ParseHostRdmaUdpPorts] UDP source port is invalid, expected a decimal integer in range [1, %u].",
63+ MultiQpSrcPortConfig::CONFIG_SRC_PORT_ID_MAX);
64+ return false;
65+ }
66+ parsedPorts.emplace_back(static_cast<std::uint16_t>(port));
67+ if (parsedPorts.size() > MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX) {
68+ HCCL_ERROR(
69+ "[ParseHostRdmaUdpPorts] UDP source port count[%zu] exceeds the maximum[%u].", parsedPorts.size(),
70+ MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX);
71+ return false;
72+ }
73+ if (comma == std::string::npos) {
74+ break;
75+ }
76+ start = comma + 1U;
77+ }
78+ ports = std::move(parsedPorts);
79+ return true;
80+}
81+ 
29/*----------------------------- cast functions -------------------------*/82/*----------------------------- cast functions -------------------------*/
30 83 
84+HostRdmaUdpPortsList CastHostRdmaUdpPortsList(const std::string& s)
85+{
86+ HostRdmaUdpPortsList list;
87+ if (s.empty()) {
88+ return list;
89+ }
90+ if (s.size() > HostRdmaUdpPortsList::CONFIG_VALUE_LEN_MAX) {
91+ HCCL_ERROR(
92+ "[CastHostRdmaUdpPortsList] config value length[%zu] exceeds the maximum[%u].", s.size(),
93+ HostRdmaUdpPortsList::CONFIG_VALUE_LEN_MAX);
94+ return {};
95+ }
96+ 
97+ size_t start = 0;
98+ while (start <= s.size()) {
欧阳茜
欧阳茜欧阳茜9月11日

[LOW] CastHostRdmaUdpPortsList 的 while (start <= s.size()) 循环与同文件刚修复的 ParseHostRdmaUdpPorts 风格不一致

CastHostRdmaUdpPortsList(line 98)使用 while (start <= s.size()) 循环,当输入以分号结尾时(如 "0:10000;")会产生一次额外迭代,依赖 deviceConfig.empty() 检查兜底。同文件刚按检视意见修复的 ParseHostRdmaUdpPorts(line 56)已改为 while(true) + find + break 模式并显式校验尾逗号。两个函数都在本 PR 中新增,逻辑高度相似(分号/逗号分隔解析),建议 CastHostRdmaUdpPortsList 也统一为 while(true) + find + break 模式,或在入口添加 s.back() == ';' 的显式校验,保持风格一致、语义清晰。

likedislike
99+ const size_t semicolon = s.find(';', start);
100+ const std::string deviceConfig
101+ = s.substr(start, semicolon == std::string::npos ? std::string::npos : semicolon - start);
102+ const size_t colon = deviceConfig.find(':');
103+ if (deviceConfig.empty() || colon == std::string::npos || colon == 0U || colon + 1U >= deviceConfig.size()
104+ || deviceConfig.find(':', colon + 1U) != std::string::npos) {
105+ HCCL_ERROR("[CastHostRdmaUdpPortsList] device config has invalid separators or an empty field.");
106+ return {};
107+ }
108+ 
109+ u32 devicePhyId = 0;
110+ if (!ParseDecimalU32(deviceConfig.substr(0, colon), devicePhyId)) {
111+ HCCL_ERROR("[CastHostRdmaUdpPortsList] phy_dev_id is not a valid decimal integer.");
112+ return {};
113+ }
114+ std::vector<std::uint16_t> ports;
115+ if (!ParseHostRdmaUdpPorts(deviceConfig.substr(colon + 1U), ports)) {
116+ return {};
117+ }
118+ if (!list.portsByPhyId.emplace(devicePhyId, std::move(ports)).second) {
119+ HCCL_ERROR("[CastHostRdmaUdpPortsList] phy_dev_id[%u] is duplicated.", devicePhyId);
120+ return {};
121+ }
122+ if (semicolon == std::string::npos) {
123+ break;
124+ }
125+ start = semicolon + 1U;
126+ }
127+ return list;
128+}
129+ 
31bool CastBin2Bool(const std::string& s)130bool CastBin2Bool(const std::string& s)
32{131{
33 bool b = true;132 bool b = true;
@@ -131,9 +230,9 @@ void GetUIntFromStr(const std::string& digitStr, u32& val)
131 CHK_PRT_THROW(230 CHK_PRT_THROW(
132 !isAllDigits, HCCL_ERROR("[GetUIntFromStr] str[%s] is not all digit.", digitStr.c_str()),231 !isAllDigits, HCCL_ERROR("[GetUIntFromStr] str[%s] is not all digit.", digitStr.c_str()),
133 InvalidParamsException, "parser portRange fail.");232 InvalidParamsException, "parser portRange fail.");
134- auto ret = SalStrToULong(digitStr.c_str(), HCCL_BASE_DECIMAL, val);233+ const bool parseSuccess = ParseDecimalU32(digitStr, val);
135 CHK_PRT_THROW(234 CHK_PRT_THROW(
136- ret != HCCL_SUCCESS, HCCL_ERROR("[GetUIntFromStr] str[%s] is a invalid number.", digitStr.c_str()),235+ !parseSuccess, HCCL_ERROR("[GetUIntFromStr] str[%s] is a invalid number.", digitStr.c_str()),
137 InvalidParamsException, "parser portRange fail.");236 InvalidParamsException, "parser portRange fail.");
138}237}
139 238 
@@ -963,6 +1062,15 @@ HcclDetourType CastDetourType(const std::string& s)
963}1062}
964 1063 
965/*----------------------- multi qp src port config --------------------------*/1064/*----------------------- multi qp src port config --------------------------*/
1065+std::vector<std::uint16_t> GetHostRdmaUdpPortsByPhyId(const HostRdmaUdpPortsList& list, u32 devicePhyId)
严正行
严正行严正行9月10日

[LOW] GetHostRdmaUdpPortsByPhyId 全仓无调用点,属本 PR 引入的死代码

问题分析:

  • 第 1044 行:std::vectorstd::uint16_t GetHostRdmaUdpPortsByPhyId(const HostRdmaUdpPortsList& list, u32 devicePhyId)

全仓 grep 仅两处命中:本处实现与 env_func.h:274 的 extern 声明,无任何调用点(消费侧 roce_channel_desc_configurator.cc:207 直接用 udpPortsList.portsByPhyId.find(devicePhyId) 访问成员,未走该 helper);该符号也未加入 hccl_v2.map 导出表,跨 so 不可见。本 PR 回应「减少符号」意见时删除了 map 导出,但保留了实现与声明,成为死代码。

建议修复: 删除 env_func.cc:1044-1051 的实现与 env_func.h:274 的 extern 声明(连同空行);若希望保留「按 phyId 查询」的语义封装,则反向处理——让 roce_channel_desc_configurator.cc:207-210 改为调用该 helper(其返回 const 引用或值拷贝均可),二选一,避免 helper 与直接成员访问并存。

likedislike
1066+{
1067+ const auto iter = list.portsByPhyId.find(devicePhyId);
1068+ if (iter == list.portsByPhyId.end()) {
1069+ return {};
1070+ }
1071+ return iter->second;
1072+}
1073+ 
966std::vector<std::uint16_t>1074std::vector<std::uint16_t>
967GetMultiQpSrcPortsByIpPair(const MultiQpSrcPortConfig& config, const IpAddress& srcIp, const IpAddress& dstIp)1075GetMultiQpSrcPortsByIpPair(const MultiQpSrcPortConfig& config, const IpAddress& srcIp, const IpAddress& dstIp)
968{1076{
@@ -260,6 +260,21 @@ struct MultiQpSrcPortConfig {
260 static constexpr u32 CONFIG_IP_NUM = 2;260 static constexpr u32 CONFIG_IP_NUM = 2;
261};261};
262 262 
263+struct HostRdmaUdpPortsList {
264+ std::unordered_map<u32, std::vector<std::uint16_t>> portsByPhyId;
265+ 
266+ bool IsAvailable() const { return !portsByPhyId.empty(); }
267+ size_t GetDeviceConfigCount() const { return portsByPhyId.size(); }
268+ 
269+ static constexpr u32 CONFIG_VALUE_LEN_MAX = 32 * 1024;
270+};
271+ 
272+extern bool ParseHostRdmaUdpPorts(const std::string& value, std::vector<std::uint16_t>& ports);
273+ 
274+extern HostRdmaUdpPortsList CastHostRdmaUdpPortsList(const std::string& s);
275+ 
276+extern std::vector<std::uint16_t> GetHostRdmaUdpPortsByPhyId(const HostRdmaUdpPortsList& list, u32 devicePhyId);
277+ 
263extern u32278extern u32
264GetMultiQpPortsNumByIpPair(const MultiQpSrcPortConfig& config, const IpAddress& srcIp, const IpAddress& dstIp);279GetMultiQpPortsNumByIpPair(const MultiQpSrcPortConfig& config, const IpAddress& srcIp, const IpAddress& dstIp);
265 280 
@@ -262,6 +262,7 @@ global:
262 "Hccl::EnvHostNicConfig::GetWhitelistDisable() const"; # _ZNK4Hccl16EnvHostNicConfig19GetWhitelistDisableEv262 "Hccl::EnvHostNicConfig::GetWhitelistDisable() const"; # _ZNK4Hccl16EnvHostNicConfig19GetWhitelistDisableEv
263 "Hccl::EnvLogConfig::GetDfsConfig() const"; # _ZNK4Hccl12EnvLogConfig12GetDfsConfigEv263 "Hccl::EnvLogConfig::GetDfsConfig() const"; # _ZNK4Hccl12EnvLogConfig12GetDfsConfigEv
264 "Hccl::EnvRdmaConfig::GetMultiQpSrcPortConfig() const"; # _ZNK4Hccl13EnvRdmaConfig23GetMultiQpSrcPortConfigEv264 "Hccl::EnvRdmaConfig::GetMultiQpSrcPortConfig() const"; # _ZNK4Hccl13EnvRdmaConfig23GetMultiQpSrcPortConfigEv
265+ "Hccl::EnvRdmaConfig::GetHostRdmaUdpPortsList() const"; # _ZNK4Hccl13EnvRdmaConfig23GetHostRdmaUdpPortsListEv
265 "Hccl::EnvRdmaConfig::GetRdmaMultiQpThreshold() const"; # _ZNK4Hccl13EnvRdmaConfig23GetRdmaMultiQpThresholdEv266 "Hccl::EnvRdmaConfig::GetRdmaMultiQpThreshold() const"; # _ZNK4Hccl13EnvRdmaConfig23GetRdmaMultiQpThresholdEv
266 "Hccl::EnvRdmaConfig::GetRdmaQueueNum() const"; # _ZNK4Hccl13EnvRdmaConfig15GetRdmaQueueNumEv267 "Hccl::EnvRdmaConfig::GetRdmaQueueNum() const"; # _ZNK4Hccl13EnvRdmaConfig15GetRdmaQueueNumEv
267 "Hccl::EnvRdmaConfig::GetRdmaRetryCnt() const"; # _ZNK4Hccl13EnvRdmaConfig15GetRdmaRetryCntEv268 "Hccl::EnvRdmaConfig::GetRdmaRetryCnt() const"; # _ZNK4Hccl13EnvRdmaConfig15GetRdmaRetryCntEv
@@ -276,6 +277,7 @@ global:
276 "Hccl::ExceptionInfo::GetErrorMsg(Hccl::ExceptionType const&)"; # _ZN4Hccl13ExceptionInfo11GetErrorMsgERKNS_13ExceptionTypeE277 "Hccl::ExceptionInfo::GetErrorMsg(Hccl::ExceptionType const&)"; # _ZN4Hccl13ExceptionInfo11GetErrorMsgERKNS_13ExceptionTypeE
277 "Hccl::GetMultiQpPortsNumByIpPair(Hccl::MultiQpSrcPortConfig const&, Hccl::IpAddress const&, Hccl::IpAddress const&)"; # _ZN4Hccl26GetMultiQpPortsNumByIpPairERKNS_20MultiQpSrcPortConfigERKNS_9IpAddressES5_278 "Hccl::GetMultiQpPortsNumByIpPair(Hccl::MultiQpSrcPortConfig const&, Hccl::IpAddress const&, Hccl::IpAddress const&)"; # _ZN4Hccl26GetMultiQpPortsNumByIpPairERKNS_20MultiQpSrcPortConfigERKNS_9IpAddressES5_
278 "Hccl::GetMultiQpSrcPortsByIpPair(Hccl::MultiQpSrcPortConfig const&, Hccl::IpAddress const&, Hccl::IpAddress const&)"; # _ZN4Hccl26GetMultiQpSrcPortsByIpPairERKNS_20MultiQpSrcPortConfigERKNS_9IpAddressES5_279 "Hccl::GetMultiQpSrcPortsByIpPair(Hccl::MultiQpSrcPortConfig const&, Hccl::IpAddress const&, Hccl::IpAddress const&)"; # _ZN4Hccl26GetMultiQpSrcPortsByIpPairERKNS_20MultiQpSrcPortConfigERKNS_9IpAddressES5_
280+ "Hccl::ParseHostRdmaUdpPorts(std::string const&, std::vector<unsigned short, std::allocator<unsigned short> >&)"; # _ZN4Hccl21ParseHostRdmaUdpPortsERKSsRSt6vectorItSaItEE
279 "Hccl::GetUbToken()"; # _ZN4Hccl10GetUbTokenEv281 "Hccl::GetUbToken()"; # _ZN4Hccl10GetUbTokenEv
280 "Hccl::GlobalMirrorTasks::FindTaskInfo(unsigned int, unsigned int, unsigned int, Hccl::TaskInfo*&) const"; # _ZNK4Hccl17GlobalMirrorTasks12FindTaskInfoEjjjRPNS_8TaskInfoE282 "Hccl::GlobalMirrorTasks::FindTaskInfo(unsigned int, unsigned int, unsigned int, Hccl::TaskInfo*&) const"; # _ZNK4Hccl17GlobalMirrorTasks12FindTaskInfoEjjjRPNS_8TaskInfoE
281 "Hccl::GlobalMirrorTasks::GetQueue(unsigned int, unsigned int) const"; # _ZNK4Hccl17GlobalMirrorTasks8GetQueueEjj283 "Hccl::GlobalMirrorTasks::GetQueue(unsigned int, unsigned int) const"; # _ZNK4Hccl17GlobalMirrorTasks8GetQueueEjj
@@ -32,6 +32,7 @@ const std::map<std::string, std::string> defaultEnvCfgMap
32 {"HCCL_RDMA_TIMEOUT", "6"},32 {"HCCL_RDMA_TIMEOUT", "6"},
33 {"HCCL_RDMA_RETRY_CNT", "5"},33 {"HCCL_RDMA_RETRY_CNT", "5"},
34 {"HCCL_RDMA_QPS_PER_CONNECTION", "1"},34 {"HCCL_RDMA_QPS_PER_CONNECTION", "1"},
35+ {"HCCL_HOST_RDMA_UDP_PORTS_LIST", ""},
35 {"HCCL_MULTI_QP_THRESHOLD", "512"},36 {"HCCL_MULTI_QP_THRESHOLD", "512"},
36 {"HCCL_INTRA_PCIE_ENABLE", "1"},37 {"HCCL_INTRA_PCIE_ENABLE", "1"},
37 {"HCCL_INTRA_ROCE_ENABLE", "0"},38 {"HCCL_INTRA_ROCE_ENABLE", "0"},
@@ -463,6 +463,73 @@ TEST_F(EnvConfigTest, Ut_GetRdmaQueueNum_OutOfRange_ReturnsException)
463 unsetenv("HCCL_RDMA_QPS_PER_CONNECTION");463 unsetenv("HCCL_RDMA_QPS_PER_CONNECTION");
464}464}
465 465 
466+TEST_F(EnvConfigTest, Ut_EnvRdmaConfigGetHostRdmaUdpPortsList_WhenValidAndEmpty_ExpectParsed)
467+{
468+ setenv("HCCL_HOST_RDMA_UDP_PORTS_LIST", "0:10000,10015;1:10016,10031", 1);
469+ EnvRdmaConfig validRdmaConfig;
470+ validRdmaConfig.Parse();
471+ const auto& validList = validRdmaConfig.GetHostRdmaUdpPortsList();
472+ const auto device0Iter = validList.portsByPhyId.find(0);
473+ ASSERT_NE(device0Iter, validList.portsByPhyId.end());
474+ EXPECT_EQ(device0Iter->second, (std::vector<std::uint16_t>{10000, 10015}));
475+ const auto device1Iter = validList.portsByPhyId.find(1);
476+ ASSERT_NE(device1Iter, validList.portsByPhyId.end());
477+ EXPECT_EQ(device1Iter->second, (std::vector<std::uint16_t>{10016, 10031}));
478+ EXPECT_EQ(validList.portsByPhyId.find(2), validList.portsByPhyId.end());
479+ 
480+ setenv("HCCL_HOST_RDMA_UDP_PORTS_LIST", "", 1);
481+ EnvRdmaConfig emptyRdmaConfig;
482+ emptyRdmaConfig.Parse();
483+ EXPECT_FALSE(emptyRdmaConfig.GetHostRdmaUdpPortsList().IsAvailable());
484+ unsetenv("HCCL_HOST_RDMA_UDP_PORTS_LIST");
485+}
486+ 
487+TEST_F(EnvConfigTest, Ut_EnvRdmaConfigParse_WhenHostRdmaUdpPortsInvalid_ExpectUnavailable)
488+{
489+ std::string tooManyPorts = "0:1";
490+ for (u32 i = 0; i < MultiQpSrcPortConfig::CONFIG_SRC_PORT_NUM_MAX; ++i) {
491+ tooManyPorts += ",1";
492+ }
493+ const std::vector<std::string> invalidValues
494+ = {"a:10000", "0:0", "0:65536", "0:10000,", "0", ":10000", "0:", "0:10000:10001", tooManyPorts};
495+ for (const auto& value : invalidValues) {
496+ SCOPED_TRACE(value);
497+ setenv("HCCL_HOST_RDMA_UDP_PORTS_LIST", value.c_str(), 1);
498+ EnvRdmaConfig rdmaConfig;
499+ EXPECT_NO_THROW(rdmaConfig.Parse());
500+ EXPECT_FALSE(rdmaConfig.GetHostRdmaUdpPortsList().IsAvailable());
501+ }
502+ unsetenv("HCCL_HOST_RDMA_UDP_PORTS_LIST");
503+}
504+ 
505+TEST_F(EnvConfigTest, Ut_EnvRdmaConfigParse_WhenHostRdmaUdpPortsPhyIdDuplicated_ExpectUnavailable)
506+{
507+ setenv("HCCL_HOST_RDMA_UDP_PORTS_LIST", "0:10000,10001;0:10002", 1);
508+ EnvRdmaConfig rdmaConfig;
509+ EXPECT_NO_THROW(rdmaConfig.Parse());
510+ EXPECT_FALSE(rdmaConfig.GetHostRdmaUdpPortsList().IsAvailable());
511+ unsetenv("HCCL_HOST_RDMA_UDP_PORTS_LIST");
512+}
513+ 
514+TEST_F(EnvConfigTest, Ut_EnvRdmaConfigParse_WhenHostRdmaUdpPortsPartiallyInvalid_ExpectUnavailable)
515+{
516+ setenv("HCCL_HOST_RDMA_UDP_PORTS_LIST", "0:10000,10001;1:0", 1);
517+ EnvRdmaConfig rdmaConfig;
518+ EXPECT_NO_THROW(rdmaConfig.Parse());
519+ EXPECT_FALSE(rdmaConfig.GetHostRdmaUdpPortsList().IsAvailable());
520+ unsetenv("HCCL_HOST_RDMA_UDP_PORTS_LIST");
521+}
522+ 
523+TEST_F(EnvConfigTest, Ut_EnvRdmaConfigParse_WhenHostRdmaUdpPortsValueTooLong_ExpectUnavailable)
524+{
525+ const std::string tooLongValue(HostRdmaUdpPortsList::CONFIG_VALUE_LEN_MAX + 1U, '0');
526+ setenv("HCCL_HOST_RDMA_UDP_PORTS_LIST", tooLongValue.c_str(), 1);
527+ EnvRdmaConfig rdmaConfig;
528+ EXPECT_NO_THROW(rdmaConfig.Parse());
529+ EXPECT_FALSE(rdmaConfig.GetHostRdmaUdpPortsList().IsAvailable());
530+ unsetenv("HCCL_HOST_RDMA_UDP_PORTS_LIST");
531+}
532+ 
466TEST_F(EnvConfigTest, Ut_GetRdmaMultiQpThreshold_ValidValue_ReturnsCorrectValue)533TEST_F(EnvConfigTest, Ut_GetRdmaMultiQpThreshold_ValidValue_ReturnsCorrectValue)
467{534{
468 setenv("HCCL_MULTI_QP_THRESHOLD", "1123", 1);535 setenv("HCCL_MULTI_QP_THRESHOLD", "1123", 1);
@@ -27,6 +27,7 @@
27#include "hccl/hccl_types.h"27#include "hccl/hccl_types.h"
28#include "hccp.h"28#include "hccp.h"
29#include "my_rank.h"29#include "my_rank.h"
30+#include "roce_channel_desc_configurator.h"
30#include "aiv_urma_channel.h"31#include "aiv_urma_channel.h"
31#include "channel_process.h"32#include "channel_process.h"
32#include "coll_comm_res_c_adpt.h"33#include "coll_comm_res_c_adpt.h"
@@ -114,7 +115,7 @@ int StubRaGetHostMultiQpCount(RaInfo* info, HccnCfgKey key, char* value, unsigne
114 }115 }
115 EXPECT_EQ(info->mode, NETWORK_PEER_ONLINE);116 EXPECT_EQ(info->mode, NETWORK_PEER_ONLINE);
116 EXPECT_EQ(info->phyId, g_hostConfigDevicePhyId);117 EXPECT_EQ(info->phyId, g_hostConfigDevicePhyId);
117- EXPECT_EQ(*valueLen, MyRankUtils::HOST_NIC_CONFIG_BUFFER_SIZE);118+ EXPECT_EQ(*valueLen, RoceChannelDescConfigurator::HOST_NIC_CONFIG_BUFFER_SIZE);
118 g_hostConfigReadKeys.emplace_back(key);119 g_hostConfigReadKeys.emplace_back(key);
119 120 
120 const std::string* configValue = nullptr;121 const std::string* configValue = nullptr;
Mtest/ut/framework/next/coll_comms/rank/ut_my_rank.cc+48-38文件内容可能有违规信息