Line data Source code
1 : /**
2 : * Copyright (c) 2025 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 <arpa/inet.h>
12 : #include <securec.h>
13 : #include <string>
14 : #include "network/hccp_common.h"
15 : #include "device_capacity.h"
16 : #include "network_manager_pub.h"
17 : #include "adapter_rts.h"
18 : #include "externalinput_pub.h"
19 : #include "hccl_network.h"
20 : #include "externalinput.h"
21 : #include "../host/transport_ibverbs.h"
22 :
23 : // 混合模式(RoCE Cross-Mode)公共类型定义
24 : #include "../../../../base_comm/resources/endpoint_pairs/channels/host/exchange_data_format.h"
25 :
26 : using namespace std;
27 : constexpr u32 RDMA_QP_EXPECT_STATUS_PAUSE = 5;
28 : constexpr u32 RDMA_QP_EXPECT_STATUS_CONNECTED = 1;
29 :
30 : namespace hccl {
31 : std::array<DeviceMem, MAX_MODULE_DEVICE_NUM> TransportIbverbs::notifyValueMem_;
32 : std::array<std::mutex, MAX_MODULE_DEVICE_NUM> TransportIbverbs::notifyValueMutex_;
33 : std::array<Referenced, MAX_MODULE_DEVICE_NUM> TransportIbverbs::instanceRef_;
34 : UniversalConcurrentMap<u64, TransportIbverbs*> TransportIbverbs::g_qpn2IbversLinkMap_;
35 : bool TransportIbverbs::g_flag = false;
36 : bool TransportIbverbs::g_isSupCqeErrInfoListConfig = false;
37 : u32 TransportIbverbs::cqeErrQpn_ = 0;
38 :
39 : constexpr u32 CQE_ARRAY_SIZE = 128;
40 : constexpr u32 DEV_PHY_ID_BIT = 32;
41 :
42 : constexpr u32 WQE_RESERVE_LENGTH = 4;
43 :
44 : constexpr u32 NOTIFY_VA_ALIGN_EIGHT = 8; // notifyVa地址8byte对齐
45 :
46 23 : TransportIbverbs::TransportIbverbs(
47 : DispatcherPub* dispatcher, const std::unique_ptr<NotifyPool>& notifyPool, MachinePara& machinePara,
48 23 : std::chrono::milliseconds timeout)
49 : : TransportNet(dispatcher, notifyPool, machinePara, timeout),
50 23 : qpsPerConnection_(1),
51 23 : notifySize_(0),
52 23 : ackNotify_(nullptr),
53 23 : dataAckNotify_(nullptr),
54 23 : access_(RA_ACCESS_LOCAL_WRITE | RA_ACCESS_REMOTE_WRITE | RA_ACCESS_REMOTE_READ),
55 23 : workFlowMode_(HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB),
56 23 : sqeCounter_(0),
57 23 : currentQP_(0),
58 46 : qpMode_(machinePara.qpMode)
59 : {
60 23 : dataNotify_ = nullptr;
61 23 : if (machinePara_.deviceLogicId >= 0 && (static_cast<u32>(machinePara_.deviceLogicId) < MAX_MODULE_DEVICE_NUM)) {
62 23 : instanceRef_[machinePara_.deviceLogicId].Ref();
63 : }
64 23 : }
65 :
66 23 : TransportIbverbs::~TransportIbverbs()
67 : {
68 23 : HCCL_DEBUG("~TransportIbverbs Enter!");
69 :
70 23 : (void)DeInit();
71 :
72 23 : if (machinePara_.deviceLogicId >= 0 && (static_cast<u32>(machinePara_.deviceLogicId) < MAX_MODULE_DEVICE_NUM)) {
73 23 : if (instanceRef_[machinePara_.deviceLogicId].Unref() == 0) {
74 3 : std::unique_lock<std::mutex> lock(notifyValueMutex_[machinePara_.deviceLogicId]);
75 3 : notifyValueMem_[machinePara_.deviceLogicId].free();
76 3 : }
77 : }
78 23 : HCCL_DEBUG("~TransportIbverbs Success!");
79 23 : }
80 :
81 34 : HcclResult TransportIbverbs::DeInit()
82 : {
83 34 : (void)DeRegMR();
84 :
85 34 : (void)DestroySignal();
86 :
87 34 : (void)DestroyQP();
88 :
89 34 : return HCCL_SUCCESS;
90 : }
91 :
92 0 : HcclResult TransportIbverbs::DeRegOneMR(QpHandle& qpHandle, MemMsg& memMsg)
93 : {
94 0 : struct MrInfoT mrInfo = {};
95 0 : mrInfo.addr = memMsg.addr;
96 0 : HcclResult ret = HrtRaMrDereg(qpHandle, &mrInfo);
97 0 : CHK_PRT_RET(
98 : ret != HCCL_SUCCESS,
99 : HCCL_ERROR("errNo[0x%016llx] in link lbv, In lbv exp deconstruct, mr dereg failed.", HCCL_ERROR_CODE(ret)),
100 : ret);
101 0 : return HCCL_SUCCESS;
102 : }
103 :
104 1 : void TransportIbverbs::DeRegMRForQPhandles(MemMsg& memMsg)
105 : {
106 1 : for (u32 j = 0; j < combineQpHandles_.size(); j++) {
107 0 : if (combineQpHandles_[j].qpHandle == nullptr) {
108 0 : continue;
109 : }
110 0 : (void)DeRegOneMR(combineQpHandles_[j].qpHandle, memMsg);
111 : }
112 1 : for (u32 j = 0; j < multiCombineQpHandles_.size(); j++) {
113 0 : if (multiCombineQpHandles_[j].qpHandle == nullptr) {
114 0 : continue;
115 : }
116 0 : (void)DeRegOneMR(multiCombineQpHandles_[j].qpHandle, memMsg);
117 : }
118 1 : }
119 :
120 34 : HcclResult TransportIbverbs::DeRegMR()
121 : {
122 : /* 销毁mr */
123 34 : std::map<uintptr_t, s32> addrMap;
124 578 : for (s32 i = 0; i < static_cast<s32>(MemType::MEM_TYPE_RESERVED); i++) {
125 544 : if (memMsg_[i].mrRegFlag == REG_VALID) {
126 : std::pair<std::map<uintptr_t, s32>::iterator, bool> res
127 1 : = addrMap.insert(std::pair<uintptr_t, s32>(reinterpret_cast<uintptr_t>(memMsg_[i].addr), 0));
128 1 : if (res.second) {
129 1 : DeRegMRForQPhandles(memMsg_[i]);
130 : }
131 : }
132 : }
133 34 : return HCCL_SUCCESS;
134 34 : }
135 :
136 0 : HcclResult TransportIbverbs::DestroyQP(QpHandle& qpHandle)
137 : {
138 0 : if (qpHandle != nullptr) {
139 0 : struct QpAttr attr {};
140 0 : CHK_RET(hrtRaGetQpAttr(qpHandle, &attr));
141 :
142 0 : g_qpn2IbversLinkMap_.Erase(((static_cast<u64>(machinePara_.localDeviceId) << DEV_PHY_ID_BIT) | attr.qpn));
143 :
144 0 : HcclResult ret = HrtRaQpDestroy(qpHandle);
145 0 : if (ret != HCCL_SUCCESS) {
146 0 : HCCL_ERROR("errNo[0x%016llx] in link lbv, lbv exp deconstruct, qp destroy failed.", HCCL_ERROR_CODE(ret));
147 : }
148 0 : qpHandle = nullptr;
149 : }
150 0 : return HCCL_SUCCESS;
151 : }
152 :
153 34 : HcclResult TransportIbverbs::DestroyQP()
154 : {
155 34 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
156 0 : CHK_RET(DestroyQP(combineQpHandles_[i].qpHandle));
157 : }
158 34 : for (u32 i = 0; i < multiCombineQpHandles_.size(); i++) {
159 0 : CHK_RET(DestroyQP(multiCombineQpHandles_[i].qpHandle));
160 : }
161 34 : return HCCL_SUCCESS;
162 : }
163 :
164 1 : HcclResult TransportIbverbs::Stop()
165 : {
166 1 : HcclResult ret = hrtRaQpBatchModify(
167 1 : nicRdmaHandle_, &combineQpHandles_[0].qpHandle, combineQpHandles_.size(), RDMA_QP_EXPECT_STATUS_PAUSE);
168 1 : if (ret != HCCL_SUCCESS) {
169 0 : HCCL_ERROR("errNo[0x%016llx] in link lbv, ra qp modify stop fail.", HCCL_ERROR_CODE(ret));
170 0 : return HCCL_E_INTERNAL;
171 : }
172 1 : return HCCL_SUCCESS;
173 : }
174 :
175 1 : HcclResult TransportIbverbs::Resume()
176 : {
177 1 : HcclResult ret = hrtRaQpBatchModify(
178 1 : nicRdmaHandle_, &combineQpHandles_[0].qpHandle, combineQpHandles_.size(), RDMA_QP_EXPECT_STATUS_CONNECTED);
179 1 : if (ret != HCCL_SUCCESS) {
180 0 : HCCL_ERROR("errNo[0x%016llx] in link lbv, ra qp modify resume fail.", HCCL_ERROR_CODE(ret));
181 0 : return HCCL_E_INTERNAL;
182 : }
183 1 : return HCCL_SUCCESS;
184 : }
185 :
186 1 : HcclResult TransportIbverbs::Init()
187 : {
188 1 : HCCL_INFO(
189 : "machineType=[%d], serverId=[%s], localDeviceId=[%d], remoteDeviceId=[%d], "
190 : "localRank=[%u], localUserRank=[%u], remoteRank=[%u], remoteUserrank=[%u], "
191 : "deviceType=[%d], inputMem=[%p], outputMem=[%p], isAicpuModeEn[%d], notifyNum[%u], "
192 : "isIndOp[%d], custom exchange data size [%llu], drainEnable[%d]",
193 : machinePara_.machineType, machinePara_.serverId.c_str(), machinePara_.localDeviceId,
194 : machinePara_.remoteDeviceId, machinePara_.localUserrank, machinePara_.localWorldRank,
195 : machinePara_.remoteUserrank, machinePara_.remoteWorldRank, machinePara_.deviceType, machinePara_.inputMem.ptr(),
196 : machinePara_.outputMem.ptr(), machinePara_.isAicpuModeEn, machinePara_.notifyNum, machinePara_.isIndOp,
197 : machinePara_.exchangeInfo.size(), machinePara_.drainEnable);
198 1 : HcclUs startut = TIME_NOW();
199 :
200 1 : if (machinePara_.userMemEnable) {
201 1 : CHK_SMART_PTR_NULL(machinePara_.inputMem);
202 0 : CHK_SMART_PTR_NULL(machinePara_.outputMem);
203 0 : CHK_SMART_PTR_NULL(notifyPool_);
204 : }
205 :
206 0 : if (machinePara_.drainEnable) {
207 0 : CHK_SMART_PTR_NULL(notifyPool_);
208 : }
209 :
210 0 : CHK_PTR_NULL(dispatcher_);
211 0 : CHK_RET(CheckDeviceId());
212 0 : CHK_RET(CheckExchangeData());
213 :
214 : // 上层初始化时保证 machinePara_.sockets 非空
215 0 : if (machinePara_.sockets.size() == 0) {
216 0 : HCCL_ERROR("machinePara sockets is empty.");
217 0 : return HCCL_E_INTERNAL;
218 : }
219 0 : defaultSocket_ = machinePara_.sockets[0];
220 0 : CHK_PTR_NULL(defaultSocket_);
221 :
222 0 : CHK_RET(hrtGetDeviceType(localDeviceType));
223 0 : HCCL_INFO("localDeviceType=[%d], remoteDeviceType=[%d]", localDeviceType, machinePara_.deviceType);
224 0 : CHK_RET(GetNicHandle());
225 :
226 : // 设置linkType
227 0 : transportAttr_.linkType = hccl::LinkType::LINK_ROCE;
228 :
229 : /* 获取当前的连接模式,offline模式或者op base模式 */
230 0 : workFlowMode_ = GetWorkflowMode();
231 0 : HCCL_INFO("current work mode is [%d]", workFlowMode_);
232 :
233 0 : CHK_RET(GetNotifySize());
234 :
235 : /* 创建QP连接 */
236 0 : CHK_RET(InitQpConnect());
237 :
238 0 : HCCL_INFO("linkexp initialization success,Time:%lld us", DURATION_US(TIME_NOW() - startut));
239 :
240 0 : CHK_RET(GetQpAttr());
241 0 : return HCCL_SUCCESS;
242 : }
243 :
244 0 : HcclResult TransportIbverbs::GetQpAttr()
245 : {
246 : char stackLogBuffer[LOG_TMPBUF_SIZE];
247 0 : s32 ret = snprintf_s(
248 : stackLogBuffer, LOG_TMPBUF_SIZE, LOG_TMPBUF_SIZE - 1U,
249 : "communicator[%s], local rank[%u], ip[%s], remote rank[%u], ip[%s], transporttype[%s]",
250 : machinePara_.tag.c_str(), machinePara_.localUserrank, machinePara_.localIpAddr.GetReadableAddress(),
251 : machinePara_.remoteUserrank, machinePara_.remoteIpAddr.GetReadableAddress(),
252 0 : GetLinkTypeEnumStr(GetLinkType()).c_str());
253 0 : CHK_PRT_RET(
254 : ret == -1, HCCL_ERROR("[GetQpAttr]errNo[0x%016llx] sal snprintf_s error", HCCL_ERROR_CODE(HCCL_E_INTERNAL)),
255 : HCCL_E_INTERNAL);
256 0 : std::string logInfo = "create hccl transport:" + std::string(stackLogBuffer);
257 0 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
258 0 : struct QpAttr attr {};
259 0 : CHK_RET(hrtRaGetQpAttr(combineQpHandles_[i].qpHandle, &attr));
260 0 : HCCL_USER_CRITICAL_LOG(
261 : "%s, rdma qpn[%u], rdma qp sport[%u], rdma TC[%u], rdma SL[%u]", logInfo.c_str(), attr.qpn, attr.udpSport,
262 : machinePara_.tc, machinePara_.sl);
263 : }
264 0 : if (UseMultiQp()) {
265 0 : for (u32 i = 0; i < multiCombineQpHandles_.size(); i++) {
266 0 : struct QpAttr attr {};
267 0 : CHK_RET(hrtRaGetQpAttr(multiCombineQpHandles_[i].qpHandle, &attr));
268 0 : HCCL_USER_CRITICAL_LOG(
269 : "%s, rdma qpn[%u], rdma qp sport[%u], rdma TC[%u], rdma SL[%u]", logInfo.c_str(), attr.qpn,
270 : attr.udpSport, machinePara_.tc, machinePara_.sl);
271 : }
272 : }
273 0 : return HCCL_SUCCESS;
274 0 : }
275 :
276 0 : HcclResult TransportIbverbs::GetNotifySize()
277 : {
278 0 : u32 notifySize = 0;
279 0 : CHK_RET(hrtGetNotifySize(notifySize));
280 0 : notifySize_ = notifySize;
281 0 : return HCCL_SUCCESS;
282 : }
283 :
284 0 : HcclResult TransportIbverbs::IsUseQpCreateWithAttrs(bool& isUseQpCreateWithAttrs, s32 qpMode)
285 : {
286 0 : isUseQpCreateWithAttrs = false;
287 0 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE) {
288 0 : bool is910Bor91093
289 0 : = machinePara_.deviceType == DevType::DEV_TYPE_910B || machinePara_.deviceType == DevType::DEV_TYPE_910_93;
290 0 : if (is910Bor91093 && (qpMode == OFFLINE_QP_MODE_EXT || qpMode == OPBASE_QP_MODE_EXT)) {
291 0 : isUseQpCreateWithAttrs = true;
292 : }
293 : }
294 0 : return HCCL_SUCCESS;
295 : }
296 :
297 8 : HcclResult TransportIbverbs::FillExchangeDataTotalSize()
298 : {
299 8 : exchangeDataTotalSize_ = 0;
300 8 : exchangeDataTotalSize_ += sizeof(u32); // 首个内容放qp数量
301 8 : if (UseMultiQp()) {
302 2 : exchangeDataTotalSize_ += sizeof(u32); // 再放个MultiQpThreshold
303 : }
304 8 : if (machinePara_.userMemEnable) {
305 4 : exchangeDataTotalSize_ += sizeof(MemMsg) * 2; // 2: output and input mem
306 4 : exchangeDataTotalSize_ += sizeof(MemMsg) * 3; // 3: dataNotify_\ackNotify_\dataAckNotify_
307 4 : if (UseMultiQp()) {
308 1 : exchangeDataTotalSize_ += qpsPerConnection_ * sizeof(MemMsg); // 多QP下新增协商内容
309 : }
310 : }
311 8 : if (machinePara_.drainEnable) {
312 1 : exchangeDataTotalSize_ += sizeof(MemMsg); // Drain用到了dataNotify_
313 1 : exchangeDataTotalSize_ += sizeof(MemMsg); // 本端notify srcmem, 用于Drain
314 : }
315 8 : if (!isHybridMode_) {
316 8 : exchangeDataTotalSize_ += machinePara_.exchangeInfo.size();
317 : }
318 :
319 : // 4.新增notify资源统计
320 : // 单qp notify资源大小:1*notifyNum, 多qp notify资源大小:qpNum*notifyNum
321 8 : exchangeDataTotalSize_ += qpsPerConnection_ * sizeof(MemMsg) * notifyNum_;
322 :
323 : // 5.新增和对端协商atomic write是否使能
324 8 : exchangeDataTotalSize_ += sizeof(u8);
325 :
326 8 : if (machinePara_.isIndOp) {
327 : // 6. userDeviceMem数量\userDeviceMem\userHostMem数量\userHostMem
328 0 : exchangeDataTotalSize_ += sizeof(u32);
329 0 : exchangeDataTotalSize_ += sizeof(MemMsg) * machinePara_.userDeviceMem.size();
330 0 : exchangeDataTotalSize_ += sizeof(u32);
331 0 : exchangeDataTotalSize_ += sizeof(MemMsg) * machinePara_.userHostMem.size();
332 : }
333 :
334 8 : HCCL_DEBUG("[TransportIbverbs][FillExchangeDataTotalSize] exchangeDataTotalSize[%llu]", exchangeDataTotalSize_);
335 8 : return HCCL_SUCCESS;
336 : }
337 :
338 0 : HcclResult TransportIbverbs::ConstructExchangeForSend()
339 : {
340 0 : exchangeDataForSend_.resize(exchangeDataTotalSize_);
341 0 : u8* exchangeDataPtr = exchangeDataForSend_.data();
342 0 : u64 exchangeDataBlankSize = exchangeDataTotalSize_;
343 : // 把qp对数量放在最前头,第一个做检验
344 0 : u32 qpNum = UseMultiQp() ? qpsPerConnection_ : 1;
345 0 : s32 sRet = memcpy_s(exchangeDataPtr, sizeof(u32), reinterpret_cast<void*>(&qpNum), sizeof(u32));
346 0 : CHK_PRT_RET(
347 : sRet != EOK,
348 : HCCL_ERROR(
349 : "[Set][LocalMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
350 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
351 : HCCL_E_MEMORY);
352 0 : exchangeDataPtr += sizeof(u32);
353 0 : exchangeDataBlankSize -= sizeof(u32);
354 :
355 0 : if (UseMultiQp()) {
356 : // 把multiQpThreshold放第二个,第二个做检验
357 0 : u32 multiQpThreshold = GetExternalInputMultiQpThreshold();
358 0 : sRet = memcpy_s(exchangeDataPtr, sizeof(u32), reinterpret_cast<void*>(&multiQpThreshold), sizeof(u32));
359 0 : CHK_PRT_RET(
360 : sRet != EOK,
361 : HCCL_ERROR(
362 : "[Set][LocalMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
363 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
364 : HCCL_E_MEMORY);
365 0 : exchangeDataPtr += sizeof(u32);
366 0 : exchangeDataBlankSize -= sizeof(u32);
367 : }
368 :
369 0 : if (machinePara_.userMemEnable) {
370 0 : CHK_RET(RegUserMem(MemType::USER_OUTPUT_MEM, exchangeDataPtr, exchangeDataBlankSize));
371 0 : CHK_RET(RegUserMem(MemType::USER_INPUT_MEM, exchangeDataPtr, exchangeDataBlankSize));
372 0 : if (machinePara_.isAicpuModeEn) {
373 0 : CHK_RET(CreateNotifyBuffer(
374 : dataNotify_, MemType::DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize,
375 : NotifyLoadType::DEVICE_NOTIFY));
376 0 : CHK_RET(CreateNotifyBuffer(
377 : ackNotify_, MemType::ACK_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize,
378 : NotifyLoadType::DEVICE_NOTIFY));
379 0 : CHK_RET(CreateNotifyBuffer(
380 : dataAckNotify_, MemType::DATA_ACK_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize,
381 : NotifyLoadType::DEVICE_NOTIFY));
382 : } else {
383 0 : CHK_RET(CreateNotifyBuffer(dataNotify_, MemType::DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
384 0 : CHK_RET(CreateNotifyBuffer(ackNotify_, MemType::ACK_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
385 0 : CHK_RET(CreateNotifyBuffer(
386 : dataAckNotify_, MemType::DATA_ACK_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
387 : }
388 : }
389 0 : if (!machinePara_.userMemEnable && machinePara_.drainEnable) {
390 0 : if (machinePara_.isAicpuModeEn) {
391 0 : CHK_RET(CreateNotifyBuffer(
392 : dataNotify_, MemType::DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize,
393 : NotifyLoadType::DEVICE_NOTIFY));
394 : } else {
395 0 : CHK_RET(CreateNotifyBuffer(dataNotify_, MemType::DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
396 : }
397 : // Drain操作需读取对端srcmem
398 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
399 : exchangeDataPtr, exchangeDataBlankSize,
400 : reinterpret_cast<void*>(&memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)]), sizeof(MemMsg)));
401 0 : exchangeDataPtr += sizeof(MemMsg);
402 0 : exchangeDataBlankSize -= sizeof(MemMsg);
403 : }
404 0 : if (!isHybridMode_) {
405 0 : CHK_RET(ConstructExchangeDataForSend(exchangeDataPtr, exchangeDataBlankSize));
406 : }
407 0 : if (machinePara_.userMemEnable && UseMultiQp()) {
408 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
409 0 : std::shared_ptr<LocalIpcNotify> oneNotify;
410 0 : if (machinePara_.isAicpuModeEn) {
411 0 : CHK_RET(CreateNotifyBuffer(
412 : oneNotify, MemType::MULTI_QP_DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize,
413 : NotifyLoadType::DEVICE_NOTIFY));
414 : } else {
415 0 : CHK_RET(CreateNotifyBuffer(
416 : oneNotify, MemType::MULTI_QP_DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
417 : }
418 0 : multiQpDataNotify_.push_back(std::move(oneNotify));
419 0 : }
420 : }
421 :
422 : // 创建notify pool资源
423 : // 单qp创建1*notifyNum个,多qp创建qpNum*notifyNum个
424 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
425 0 : std::vector<std::shared_ptr<LocalIpcNotify>> notifyVec;
426 0 : CHK_RET(CreateNotifyVectorBuffer(notifyVec, exchangeDataPtr, exchangeDataBlankSize));
427 0 : userMultiQpLocalNotify_.push_back(std::move(notifyVec));
428 0 : }
429 :
430 0 : u8 localEnableAtomicWrite = machinePara_.enableAtomicWrite ? 1 : 0;
431 0 : sRet = memcpy_s(exchangeDataPtr, sizeof(u8), reinterpret_cast<void*>(&localEnableAtomicWrite), sizeof(u8));
432 0 : CHK_PRT_RET(
433 : sRet != EOK,
434 : HCCL_ERROR(
435 : "[Set][LocalMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu], cnt[%zu]",
436 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(bool), sizeof(bool)),
437 : HCCL_E_MEMORY);
438 0 : exchangeDataPtr += sizeof(u8);
439 0 : exchangeDataBlankSize -= sizeof(u8);
440 :
441 0 : if (machinePara_.isIndOp) {
442 0 : CHK_RET(RegCustomUserMem(exchangeDataPtr, exchangeDataBlankSize));
443 : }
444 :
445 0 : if (exchangeDataBlankSize != 0) {
446 0 : HCCL_ERROR(
447 : "[TransportIbverbs][ConstructExchangeForSend] failed to construct exchange Data "
448 : "exchangeDataBlankSize[%llu]",
449 : exchangeDataBlankSize);
450 0 : return HCCL_E_INTERNAL;
451 : }
452 :
453 0 : HCCL_DEBUG("[TransportIbverbs] ConstructExchangeForSend finished.");
454 0 : return HCCL_SUCCESS;
455 : }
456 :
457 0 : HcclResult TransportIbverbs::ParseReceivedExchangeData()
458 : {
459 0 : u8* exchangeDataPtr = exchangeDataForRecv_.data();
460 0 : u64 exchangeDataBlankSize = exchangeDataTotalSize_;
461 :
462 : // 首先解析qp对数量,并作一致性校验
463 0 : u32 localQpNum = UseMultiQp() ? qpsPerConnection_ : 1;
464 0 : u32 remoteQpNum = 0;
465 0 : s32 sRet = memcpy_s(reinterpret_cast<void*>(&remoteQpNum), sizeof(u32), exchangeDataPtr, sizeof(u32));
466 0 : CHK_PRT_RET(
467 : sRet != EOK,
468 : HCCL_ERROR(
469 : "[Get][RemoteMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
470 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
471 : HCCL_E_MEMORY);
472 0 : CHK_PRT_RET(
473 : localQpNum != remoteQpNum,
474 : HCCL_ERROR(
475 : "[TransportIbverbs][ParseReceivedExchangeData]"
476 : "local qps[%u] not equal to remote qps[%u], rank:local[%u],remote[%u]",
477 : localQpNum, remoteQpNum, machinePara_.localUserrank, machinePara_.remoteUserrank),
478 : HCCL_E_INTERNAL);
479 0 : exchangeDataPtr += sizeof(u32);
480 0 : exchangeDataBlankSize -= sizeof(u32);
481 :
482 0 : if (UseMultiQp()) {
483 : // 再解析multiQpThreshold,并作一致性校验
484 0 : u32 localmultiQpThreshold = GetExternalInputMultiQpThreshold();
485 0 : u32 remotemultiQpThreshold = 0;
486 0 : sRet = memcpy_s(reinterpret_cast<void*>(&remotemultiQpThreshold), sizeof(u32), exchangeDataPtr, sizeof(u32));
487 0 : CHK_PRT_RET(
488 : sRet != EOK,
489 : HCCL_ERROR(
490 : "[Get][RemoteMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
491 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
492 : HCCL_E_MEMORY);
493 0 : CHK_PRT_RET(
494 : localmultiQpThreshold != remotemultiQpThreshold,
495 : HCCL_ERROR(
496 : "[TransportIbverbs][ParseReceivedExchangeData]"
497 : "local env HCCL_MULTI_QP_THRESHOLD[%u] not equal to remote env HCCL_MULTI_QP_THRESHOLD[%u], "
498 : "rank:local[%u],remote[%u]",
499 : localmultiQpThreshold, remotemultiQpThreshold, machinePara_.localUserrank, machinePara_.remoteUserrank),
500 : HCCL_E_INTERNAL);
501 0 : exchangeDataPtr += sizeof(u32);
502 0 : exchangeDataBlankSize -= sizeof(u32);
503 : }
504 :
505 0 : if (machinePara_.userMemEnable) {
506 0 : CHK_RET(GetRemoteAddr(MemType::USER_OUTPUT_MEM, exchangeDataPtr, exchangeDataBlankSize));
507 0 : CHK_RET(GetRemoteAddr(MemType::USER_INPUT_MEM, exchangeDataPtr, exchangeDataBlankSize));
508 0 : CHK_RET(GetRemoteAddr(MemType::DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
509 0 : s32 sret = memcpy_s(
510 0 : &remoteDataNotifyMsg_, sizeof(MemMsg), &remoteMemMsg_[static_cast<u32>(MemType::DATA_NOTIFY_MEM)],
511 : sizeof(MemMsg));
512 0 : CHK_PRT_RET(
513 : sret != EOK,
514 : HCCL_ERROR(
515 : "[Get][RemoteMem]errNo[0x%016llx] In lbv exp init, memory copy failed. errorno[%d], "
516 : "params:destMaxSize[%zu],count[%zu]",
517 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sret, sizeof(MemMsg), sizeof(MemMsg)),
518 : HCCL_E_MEMORY);
519 0 : CHK_RET(GetRemoteAddr(MemType::ACK_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
520 0 : CHK_RET(GetRemoteAddr(MemType::DATA_ACK_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
521 : }
522 0 : if (!machinePara_.userMemEnable && machinePara_.drainEnable) {
523 0 : CHK_RET(GetRemoteAddr(MemType::DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
524 0 : CHK_RET(GetRemoteAddr(MemType::NOTIFY_SRC_MEM, exchangeDataPtr, exchangeDataBlankSize));
525 : }
526 :
527 0 : if (!isHybridMode_) {
528 0 : CHK_RET(ParseExchangeData(exchangeDataPtr, exchangeDataBlankSize));
529 : }
530 :
531 0 : if (machinePara_.userMemEnable && UseMultiQp()) {
532 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
533 0 : CHK_RET(GetRemoteAddr(MemType::MULTI_QP_DATA_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize));
534 : }
535 : }
536 :
537 : // 解析远端新增的notify资源,二维vec大小:qpNum*notifyNum
538 0 : userMultiQpRemoteNotifyMsg_.resize(qpsPerConnection_);
539 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
540 0 : userMultiQpRemoteNotifyMsg_[i].resize(notifyNum_);
541 0 : for (u32 j = 0; j < notifyNum_; j++) {
542 0 : CHK_RET(GetRemoteNotifyAddr(exchangeDataPtr, exchangeDataBlankSize, userMultiQpRemoteNotifyMsg_[i][j]));
543 : }
544 : }
545 :
546 : // 解析远端是否都支持atomic write,仅本端和对端都支持时才使能atomic write
547 0 : u8 remoteEnableAtomicWrite = 0;
548 0 : sRet = memcpy_s(reinterpret_cast<void*>(&remoteEnableAtomicWrite), sizeof(u8), exchangeDataPtr, sizeof(u8));
549 0 : CHK_PRT_RET(
550 : sRet != EOK,
551 : HCCL_ERROR(
552 : "[Get][RemoteMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu], cnt[%zu]",
553 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(bool), sizeof(bool)),
554 : HCCL_E_MEMORY);
555 0 : useAtomicWrite_ = machinePara_.enableAtomicWrite && (remoteEnableAtomicWrite != 0);
556 0 : HCCL_INFO(
557 : "atomic write enable only when both the local and remote support, local[%d], remote[%d], result[%d]",
558 : machinePara_.enableAtomicWrite, remoteEnableAtomicWrite, useAtomicWrite_);
559 0 : exchangeDataPtr += sizeof(u8);
560 0 : exchangeDataBlankSize -= sizeof(u8);
561 :
562 0 : if (machinePara_.isIndOp) {
563 0 : CHK_RET(GetIndOpRemoteAddr(exchangeDataPtr, exchangeDataBlankSize));
564 : }
565 :
566 0 : if (exchangeDataBlankSize != 0) {
567 0 : HCCL_ERROR(
568 : "[TransportIbverbs][ParseReceivedExchangeData] failed to Parse exchange Data "
569 : "exchangeDataBlankSize[%llu]",
570 : exchangeDataBlankSize);
571 0 : return HCCL_E_INTERNAL;
572 : }
573 0 : HCCL_DEBUG("Parse Received ExchangeData success!");
574 0 : return HCCL_SUCCESS;
575 : }
576 :
577 0 : void TransportIbverbs::ModifyAtomicWriteAfterReduce(u32& preWrOpcode, u64 wqeType, u32& opcode, u32& immData)
578 : {
579 0 : bool isNotifyWqe = wqeType == static_cast<u64>(WqeType::WQE_TYPE_DATA_NOTIFY)
580 0 : || wqeType == static_cast<u64>(WqeType::WQE_TYPE_ACK_NOTIFY)
581 0 : || wqeType == static_cast<u64>(WqeType::WQE_TYPE_DATA_ACK_NOTIFY);
582 0 : if (useAtomicWrite_ && preWrOpcode == RA_WR_RDMA_REDUCE_WRITE && isNotifyWqe) {
583 0 : opcode = RA_WR_RDMA_ATOMIC_WRITE;
584 0 : immData = machinePara_.isAicpuModeEn ? htobe32(0x1) : 0x1; // aicpu展开时,HCCL直调RoCE驱动,需进行字节序转换
585 : }
586 0 : HCCL_DEBUG(
587 : "%s preWrOpcode[%u] useAtomicWrite[%d] wqeType[%d] opcode[0x%x] immdata[%u]", __func__, preWrOpcode,
588 : useAtomicWrite_, wqeType, opcode, immData);
589 0 : preWrOpcode = opcode;
590 0 : }
591 :
592 0 : u32 TransportIbverbs::GetQpsPerConnection()
593 : {
594 0 : u32 externalQps = std::max(static_cast<u32>(machinePara_.srcPorts.size()), 1U);
595 0 : s32 qpMode = GetQpMode();
596 0 : if (GetWorkflowMode() != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE
597 0 : && externalQps != HCCL_QPS_PER_CONNECTION_DEFAULT) {
598 0 : HCCL_RUN_INFO(
599 : "HCCL_RDMA_QPS_PER_CONNECTION is set to [%u] but it is not effective in offline mode.", externalQps);
600 0 : } else if (qpMode != OPBASE_QP_MODE_EXT && externalQps > 1) {
601 0 : HCCL_RUN_INFO(
602 : "HCCL_RDMA_QPS_PER_CONNECTION is set to [%u] but current devType[%d] does not support multi-QP.",
603 : externalQps, machinePara_.deviceType);
604 0 : return 1; // 非单算子模式仅支持单QP, QPS = 1
605 : }
606 0 : if (GetWorkflowMode() == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
607 0 : return externalQps; // only work for opbase mode
608 : }
609 0 : return 1; // 非单算子模式仅支持单QP, QPS = 1
610 : }
611 :
612 0 : HcclResult TransportIbverbs::GetNicHandle()
613 : {
614 0 : RaResourceInfo raResourceInfo;
615 0 : CHK_RET(NetworkManager::GetInstance(machinePara_.deviceLogicId).GetRaResourceInfo(raResourceInfo));
616 0 : std::map<HcclIpAddress, IpSocket>& tmpSocketMap = machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE ?
617 : raResourceInfo.nicSocketMap :
618 : raResourceInfo.hostNetSocketMap;
619 :
620 0 : HcclIpAddress localIpAddr = machinePara_.localIpAddr;
621 :
622 : // 获取 nicRdmaHandle
623 0 : auto itSocket = tmpSocketMap.find(localIpAddr);
624 0 : if (itSocket == tmpSocketMap.end()) {
625 0 : HCCL_ERROR(
626 : "[Get][NicHandle]In get nic handle, can not find socket handle, handle size[%u], "
627 : "local ip[%s]",
628 : tmpSocketMap.size(), localIpAddr.GetReadableAddress());
629 0 : return HCCL_E_PARA;
630 : }
631 :
632 0 : nicRdmaHandle_ = itSocket->second.nicRdmaHandle;
633 0 : CHK_PTR_NULL(nicRdmaHandle_);
634 :
635 0 : return HCCL_SUCCESS;
636 0 : }
637 :
638 0 : inline static void MultiQpAdjustQpCapacity(struct QpExtAttrs& attrs)
639 : {
640 0 : constexpr int multiQpCapacityRatio = 2;
641 0 : attrs.qpAttr.cap.max_send_wr /= multiQpCapacityRatio;
642 0 : attrs.cqAttr.sendCqDepth /= multiQpCapacityRatio;
643 0 : }
644 :
645 : // 创建一个QP
646 0 : HcclResult TransportIbverbs::CreateOneQp(
647 : s32 qpMode, u32 qpsPerConnection, QpHandle& qpHandle, AiQpInfo& aiQpInfo, bool useAicpu, u32 udpSport)
648 : {
649 0 : bool isUseQpCreateWithAttrs = false;
650 0 : CHK_RET(IsUseQpCreateWithAttrs(isUseQpCreateWithAttrs, qpMode));
651 : HcclResult ret;
652 0 : std::string useAicpuTitle = useAicpu ? std::string("aicpu ") : std::string("");
653 0 : std::string qpInfo = useAicpuTitle + std::string("rank:") + std::to_string(machinePara_.localWorldRank)
654 0 : + std::string(",localUserrank:") + std::to_string(machinePara_.localUserrank)
655 0 : + std::string(",localIpAddr: ") + std::string(machinePara_.localIpAddr.GetReadableAddress())
656 0 : + std::string(",deviceLogicId:") + std::to_string(machinePara_.deviceLogicId);
657 0 : struct QpExtAttrs attrs {};
658 : // 判断是否为NORMALQP需要使用qpMode_; hostnic场景的qpmode也是NORMALQP
659 0 : if (useAicpu || qpMode_ == QPMode::NORMAL) {
660 0 : bool isWorkFlowLib = (workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB);
661 0 : CHK_RET(ConstructQpAttrs(qpMode, attrs, machinePara_.queueDepthAttr, isWorkFlowLib));
662 0 : bool isA3Aicpu = machinePara_.isAicpuModeEn && (machinePara_.deviceType == DevType::DEV_TYPE_910_93);
663 0 : if (isA3Aicpu && workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE
664 0 : && qpMode == OPBASE_QP_MODE_EXT) {
665 0 : attrs.qpAttr.cap.max_send_wr = machinePara_.queueDepthAttr.sqDepth == INVALID_UINT ?
666 : AICPU_SQ_CQ_DEPTH :
667 0 : attrs.qpAttr.cap.max_send_wr;
668 0 : attrs.cqAttr.sendCqDepth = machinePara_.queueDepthAttr.sendCqDepth == INVALID_UINT ?
669 : AICPU_SQ_CQ_DEPTH :
670 : attrs.cqAttr.sendCqDepth;
671 : }
672 : // A3 aicpu图模式使用单个qp, qp深度为socket数量*128
673 0 : bool isAicpuLib = machinePara_.isAicpuModeEn && (machinePara_.deviceType == DevType::DEV_TYPE_910_93)
674 0 : && (workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB);
675 0 : if (!UseMultiQp() && isAicpuLib) {
676 0 : attrs.qpAttr.cap.max_send_wr = machinePara_.sockets.size() * DEFAULT_OFFLINE_MAX_SEND_WR;
677 0 : } else if (UseMultiQp()) {
678 0 : MultiQpAdjustQpCapacity(attrs);
679 : }
680 0 : HCCL_DEBUG(
681 : "qp set max_send_wr %u, socket size %u, isWorkFlowLib %d", attrs.qpAttr.cap.max_send_wr,
682 : machinePara_.sockets.size(), isWorkFlowLib);
683 :
684 0 : attrs.udpSport = udpSport;
685 0 : ret = hrtRaAiQpCreate(machinePara_.localDeviceId, nicRdmaHandle_, &attrs, &aiQpInfo, qpHandle);
686 0 : HCCL_DEBUG("aiQpAddr:%llu db_index:%u, sq_index=%u", aiQpInfo.aiQpAddr, aiQpInfo.dbIndex, aiQpInfo.sqIndex);
687 0 : qpInfo = qpInfo + std::string(",sendCqDepth:") + std::to_string(attrs.cqAttr.sendCqDepth);
688 0 : } else if (!isUseQpCreateWithAttrs && qpsPerConnection == HCCL_QPS_PER_CONNECTION_DEFAULT) {
689 0 : ret = HrtRaQpCreate(nicRdmaHandle_, QP_FLAG_RC, qpMode, qpHandle);
690 0 : } else if (!isUseQpCreateWithAttrs && qpsPerConnection != HCCL_QPS_PER_CONNECTION_DEFAULT) {
691 0 : HCCL_ERROR("qpsPerConnection[%u] is set but qpMode[%d] is not supported", qpsPerConnection, qpMode);
692 0 : return HCCL_E_PARA;
693 : } else {
694 0 : CHK_RET(ConstructQpAttrs(qpMode, attrs, machinePara_.queueDepthAttr));
695 0 : if (machinePara_.deviceType == DevType::DEV_TYPE_910_93 && !machinePara_.isAicpuModeEn
696 0 : && workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE && qpMode == OPBASE_QP_MODE_EXT) {
697 : attrs.qpAttr.cap.max_send_wr
698 0 : = machinePara_.queueDepthAttr.sqDepth == INVALID_UINT ? HOST_SQ_CQ_DEPTH : attrs.qpAttr.cap.max_send_wr;
699 : attrs.cqAttr.sendCqDepth
700 0 : = machinePara_.queueDepthAttr.sendCqDepth == INVALID_UINT ? HOST_SQ_CQ_DEPTH : attrs.cqAttr.sendCqDepth;
701 : }
702 0 : if (UseMultiQp()) {
703 0 : MultiQpAdjustQpCapacity(attrs);
704 : }
705 0 : attrs.udpSport = udpSport;
706 0 : ret = hrtRaQpCreateWithAttrs(nicRdmaHandle_, &attrs, qpHandle);
707 0 : qpInfo = qpInfo + std::string(",sendCqDepth:") + std::to_string(attrs.cqAttr.sendCqDepth);
708 : }
709 :
710 0 : RPT_ENV_ERR(
711 : ret != 0 || (qpHandle == nullptr), "EI0007", vector<string>({"resource_type", "resource_info"}),
712 : vector<string>({"qp", "CreateOneQp"}));
713 :
714 0 : CHK_PRT_RET(
715 : ret != HCCL_SUCCESS,
716 : HCCL_ERROR(
717 : "[%s][%s]create qp failed, localDeviceId[%d], qpMode[%d]", LOG_KEYWORDS_INIT_GROUP.c_str(),
718 : LOG_KEYWORDS_RESOURCE.c_str(), machinePara_.localDeviceId, qpMode),
719 : HCCL_E_ROCE_CONNECT);
720 :
721 : // 表示没有通过config配置,则使用环境变量配置
722 0 : CHK_RET(SetQpAttrQos(qpHandle, machinePara_.tc, machinePara_.sl));
723 : // 配置RDMA Timeout时间
724 0 : CHK_RET(SetQpAttrTimeOut(qpHandle, machinePara_.retryInterval));
725 : // 配置RDMA Retry Cnt重传次数
726 0 : CHK_RET(SetQpAttrRetryCnt(qpHandle, machinePara_.retryCnt));
727 : // qpn map 插入
728 0 : struct QpAttr attr {};
729 0 : CHK_RET(hrtRaGetQpAttr(qpHandle, &attr));
730 :
731 0 : g_qpn2IbversLinkMap_.Emplace(((static_cast<u64>(machinePara_.localDeviceId) << DEV_PHY_ID_BIT) | attr.qpn), this);
732 :
733 0 : HCCL_DEBUG("ra qp create success, use input udpSport[%u].", udpSport);
734 0 : return HCCL_SUCCESS;
735 0 : }
736 :
737 0 : HcclResult TransportIbverbs::CreateSingleQp(s32 qpMode) // 根据socket个数创建QP(下沉模板不够用多QP)
738 : {
739 0 : u32 socketNum = 1;
740 : // A3 aicpu图模式只使用1个qp,qp深度为socketNum*128,最大不超过32K
741 0 : bool isAicpuLib = machinePara_.isAicpuModeEn && (machinePara_.deviceType == DevType::DEV_TYPE_910_93)
742 0 : && (workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB);
743 0 : if (!UseMultiQp() && !isAicpuLib) {
744 0 : socketNum = machinePara_.sockets.size();
745 : }
746 : // 原来是 machinePara_.socketFdHandles 换成 machinePara_.sockets
747 0 : for (u32 i = 0; i < socketNum; i++) {
748 0 : QpHandle qpHandle = nullptr;
749 0 : u32 udpSport = machinePara_.srcPorts.empty() ? 0 : machinePara_.srcPorts[0];
750 0 : CHK_RET(CreateOneQp(
751 : qpMode, HCCL_QPS_PER_CONNECTION_DEFAULT, qpHandle, combineAiQpInfo_.aiQpInfo, machinePara_.isAicpuModeEn,
752 : udpSport));
753 0 : CombineQpHandle tmpCombineQpHandle;
754 0 : tmpCombineQpHandle.qpHandle = qpHandle;
755 0 : combineQpHandles_.push_back(tmpCombineQpHandle);
756 : }
757 0 : return HCCL_SUCCESS;
758 : }
759 :
760 0 : HcclResult TransportIbverbs::CreateMultiQp(s32 qpMode, u32 qpsPerConnection)
761 : {
762 : // 配置了多qp源端口号时的处理流程
763 0 : if (machinePara_.srcPorts.size() > 0) {
764 0 : HCCL_DEBUG("[TransportIbverbs][CreateMultiQp]use Multi qp create qps.");
765 : // 创建qp
766 0 : for (const auto& port : machinePara_.srcPorts) {
767 0 : QpHandle qpHandle = nullptr;
768 0 : AiQpInfo tmpAiQpInfo{};
769 0 : CHK_RET(CreateOneQp(qpMode, qpsPerConnection, qpHandle, tmpAiQpInfo, machinePara_.isAicpuModeEn, port));
770 0 : multiCombineQpHandles_.push_back(CombineQpHandle(qpHandle));
771 0 : combineAiQpInfos_.push_back(CombineQpInfo(tmpAiQpInfo));
772 : }
773 : }
774 0 : HCCL_DEBUG("ra multi-qp creation success.");
775 0 : return HCCL_SUCCESS;
776 : }
777 :
778 12 : s32 TransportIbverbs::GetQpMode()
779 : {
780 12 : s32 qpMode = NORMAL_QP_MODE;
781 :
782 12 : if (qpMode_ == QPMode::NORMAL) {
783 0 : return qpMode;
784 : }
785 :
786 12 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE) {
787 12 : if (workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
788 0 : qpMode = (machinePara_.deviceType == DevType::DEV_TYPE_910B
789 0 : || machinePara_.deviceType == DevType::DEV_TYPE_910_93) ?
790 : OPBASE_QP_MODE_EXT :
791 : OPBASE_QP_MODE;
792 : // isCapture需要创建下沉QP
793 0 : qpMode = (qpMode == OPBASE_QP_MODE_EXT && qpMode_ == QPMode::OFFLOAD) ? OFFLINE_QP_MODE_EXT : qpMode;
794 0 : isCapture_ = (qpMode == OFFLINE_QP_MODE_EXT) ? true : false;
795 : } else {
796 12 : qpMode = (machinePara_.deviceType == DevType::DEV_TYPE_910B
797 12 : || machinePara_.deviceType == DevType::DEV_TYPE_910_93) ?
798 : OFFLINE_QP_MODE_EXT :
799 : OFFLINE_QP_MODE;
800 : }
801 : }
802 12 : if (machinePara_.isAicpuModeEn) {
803 3 : qpMode = (machinePara_.deviceType == DevType::DEV_TYPE_910B
804 3 : || machinePara_.deviceType == DevType::DEV_TYPE_910_93) ?
805 : OPBASE_QP_MODE_EXT :
806 : OPBASE_QP_MODE;
807 : }
808 12 : return qpMode;
809 : }
810 :
811 12 : bool TransportIbverbs::UseMultiQp()
812 : {
813 12 : s32 qpMode = GetQpMode();
814 12 : HCCL_DEBUG("[TransportIbverbs]UseMultiQp qpsPerConnection[%u]", qpsPerConnection_);
815 12 : if (qpMode == OPBASE_QP_MODE_EXT && qpsPerConnection_ > 1) {
816 3 : return true;
817 : }
818 9 : return false;
819 : }
820 :
821 0 : HcclResult TransportIbverbs::CreateQp()
822 : {
823 0 : s32 qpMode = GetQpMode();
824 0 : HCCL_DEBUG("[TransportIbverbs][CreateQp] QpMode[%u]", qpMode);
825 0 : CHK_RET(CreateSingleQp(qpMode));
826 0 : if (UseMultiQp()) {
827 0 : HCCL_DEBUG("[TransportIbverbs]Create MultiQP begin");
828 0 : CHK_RET(CreateMultiQp(qpMode, qpsPerConnection_));
829 : }
830 0 : HCCL_DEBUG("ra qp create %u qp success.", combineQpHandles_.size());
831 0 : return HCCL_SUCCESS;
832 : }
833 :
834 0 : HcclResult TransportIbverbs::InitQpConnect()
835 : {
836 : /* 创建QP操作句柄 */
837 0 : qpsPerConnection_ = GetQpsPerConnection();
838 :
839 0 : CHK_RET(ExchangeCapabilityHybrid());
840 :
841 0 : CHK_RET(CreateQp());
842 :
843 0 : CHK_RET(FillExchangeDataTotalSize());
844 :
845 : // 注册notify 内存信息
846 0 : CHK_RET(CreateNotifyValueBuffer());
847 :
848 0 : CHK_RET(ConstructExchangeForSend());
849 0 : HCCL_DEBUG("[TransportIbverbs] resource create done exchangeDataTotalSize_[%llu]", exchangeDataTotalSize_);
850 :
851 0 : HcclResult ret = defaultSocket_->Send(exchangeDataForSend_.data(), exchangeDataTotalSize_);
852 0 : CHK_PRT_RET(
853 : ret != HCCL_SUCCESS,
854 : HCCL_ERROR(
855 : "[TransportIbverbs][InitQpConnect] failed to send exchangeData exchangeDataTotalSize[%llu], "
856 : "custom exchange data size [%llu].",
857 : exchangeDataTotalSize_, machinePara_.exchangeInfo.size()),
858 : ret);
859 0 : HCCL_DEBUG("[TransportIbverbs]Seocket Send finished, exchangeDataTotalSize[%llu]", exchangeDataTotalSize_);
860 :
861 0 : exchangeDataForRecv_.resize(exchangeDataTotalSize_);
862 0 : ret = defaultSocket_->Recv(exchangeDataForRecv_.data(), exchangeDataTotalSize_);
863 0 : CHK_PRT_RET(
864 : ret != HCCL_SUCCESS,
865 : HCCL_ERROR(
866 : "[TransportIbverbs][InitQpConnect] failed to recv exchangeData exchangeDataTotalSize[%llu], "
867 : "custom exchange data size [%llu].",
868 : exchangeDataTotalSize_, machinePara_.exchangeInfo.size()),
869 : ret);
870 :
871 0 : HCCL_DEBUG("[TransportIbverbs][Init] Socket Data Recved");
872 :
873 0 : CHK_RET(ParseReceivedExchangeData());
874 :
875 : // 连接Qp
876 0 : CHK_RET(ConnectQp());
877 0 : HCCL_INFO("In link ibv, qp status has ready");
878 0 : return HCCL_SUCCESS;
879 : }
880 :
881 0 : HcclResult TransportIbverbs::ConnectSingleQp(std::function<bool()> needStop)
882 : {
883 : // QP建链
884 0 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
885 0 : CHK_RET(HrtRaQpConnectAsync(combineQpHandles_[i].qpHandle, machinePara_.sockets[i]->GetFdHandle(), needStop));
886 : }
887 : // 查询QP建链是否成功
888 0 : s32 qpStatus = 0;
889 0 : s32 raRet = 0;
890 0 : auto startTime = std::chrono::steady_clock::now();
891 0 : HCCL_INFO("In link ibv, waiting for qp status ready...");
892 0 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
893 : while (true) {
894 0 : CHK_PRT_RET(needStop(), HCCL_ERROR("Terminating operation due to external request"), HCCL_E_INTERNAL);
895 :
896 0 : if ((std::chrono::steady_clock::now() - startTime) >= timeout_) {
897 0 : HCCL_ERROR("[Connect][Qp]get qp status timeout_=[%lld ms], qp_status=[%d]", timeout_, qpStatus);
898 0 : return HCCL_E_TIMEOUT;
899 : }
900 0 : raRet = hrtGetRaQpStatus(combineQpHandles_[i].qpHandle, &qpStatus);
901 0 : if ((!raRet) && (qpStatus == 1)) { // 为1时,qp 建链成功
902 0 : HCCL_INFO("In link ibv, %u of %u QP get status success.", (i + 1), combineQpHandles_.size());
903 0 : break;
904 : } else {
905 : // qp建链需要时间,获取qp状态直至超时
906 0 : SaluSleep(WAIT_US_COUNT);
907 : }
908 : }
909 : }
910 0 : return HCCL_SUCCESS;
911 : }
912 :
913 0 : HcclResult TransportIbverbs::ConnectMultiQp(u32 qpsPerConnection, std::function<bool()> needStop)
914 : {
915 : // 多QP下,复用同一个socket handle来modify QP, 此时需要串行创建
916 0 : if (machinePara_.sockets.size() != 2) { // 2:多QP下需要一个额外的Socket来做QP状态迁移同步
917 0 : return HCCL_E_INTERNAL;
918 : }
919 0 : for (u32 i = 0; i < qpsPerConnection; i++) {
920 : // QP建链
921 0 : u8 localQpConnectReady = 1;
922 0 : u8 remoteQpConnectReady = 0;
923 0 : CHK_RET(machinePara_.sockets[1]->Send(&localQpConnectReady, 1));
924 0 : CHK_RET(machinePara_.sockets[1]->Recv(&remoteQpConnectReady, 1));
925 0 : std::string aicpu = machinePara_.isAicpuModeEn ? "aicpu" : "";
926 0 : CHK_PRT_RET(
927 : remoteQpConnectReady != localQpConnectReady,
928 : HCCL_ERROR(
929 : "[TransportIbverbs] %s multi Qp Connected checking failed! %u of %u QP", aicpu.c_str(), (i + 1),
930 : qpsPerConnection),
931 : HCCL_E_NETWORK);
932 0 : CHK_RET(
933 : HrtRaQpConnectAsync(multiCombineQpHandles_[i].qpHandle, machinePara_.sockets[0]->GetFdHandle(), needStop));
934 : // 查询QP建链是否成功
935 0 : s32 qpStatus = 0;
936 0 : s32 raRet = 0;
937 0 : auto startTime = std::chrono::steady_clock::now();
938 0 : HCCL_INFO(
939 : "In link ibv, waiting for qp status ready... %u of %u %s QP", (i + 1), multiCombineQpHandles_.size(),
940 : aicpu.c_str());
941 : while (true) {
942 0 : if ((std::chrono::steady_clock::now() - startTime) >= timeout_) {
943 0 : HCCL_ERROR(
944 : "[Connect][Qp]get qp status timeout_=[%lld ms], qp_status=[%d], index[%u]", timeout_, qpStatus, i);
945 0 : return HCCL_E_TIMEOUT;
946 : }
947 0 : raRet = hrtGetRaQpStatus(multiCombineQpHandles_[i].qpHandle, &qpStatus);
948 0 : if ((!raRet) && (qpStatus == 1)) { // 为1时,qp 建链成功
949 0 : HCCL_INFO(
950 : "In link ibv, %u of %u %s QP get status success.", (i + 1), multiCombineQpHandles_.size(),
951 : aicpu.c_str());
952 0 : break;
953 : } else {
954 : // qp建链需要时间,获取qp状态直至超时
955 0 : SaluSleep(WAIT_US_COUNT);
956 : }
957 : }
958 0 : }
959 0 : return HCCL_SUCCESS;
960 : }
961 :
962 0 : HcclResult TransportIbverbs::ConnectQp()
963 : {
964 0 : CHK_RET(ConnectSingleQp([this]() -> bool {
965 : return this->GetStopFlag();
966 : }));
967 0 : if (UseMultiQp()) {
968 0 : CHK_RET(ConnectMultiQp(qpsPerConnection_, [this]() -> bool {
969 : return this->GetStopFlag();
970 : }));
971 : }
972 0 : return HCCL_SUCCESS;
973 : }
974 :
975 1 : HcclResult TransportIbverbs::Fence()
976 : {
977 1 : fence_ = true;
978 1 : return HCCL_SUCCESS;
979 : }
980 :
981 1 : HcclResult TransportIbverbs::AddWqeList(
982 : void* dstMemPtr, const void* srcMemPtr, u64 srcMemSize, WqeType wqeType, WrAuxInfo& aux,
983 : std::vector<WqeInfo>& wqeInfoVec)
984 : {
985 1 : WqeInfo wqeInfoTmp;
986 :
987 1 : wqeInfoTmp.wqeData.dstAddr = static_cast<u64>(reinterpret_cast<uintptr_t>(dstMemPtr));
988 1 : wqeInfoTmp.wqeData.sendFlags = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
989 1 : fence_ = false;
990 1 : wqeInfoTmp.wqeData.memList.addr = static_cast<u64>(reinterpret_cast<uintptr_t>(srcMemPtr));
991 1 : wqeInfoTmp.wqeData.memList.len = srcMemSize;
992 1 : wqeInfoTmp.wqeData.memList.lkey = 0;
993 :
994 1 : switch (wqeType) {
995 0 : case WqeType::WQE_TYPE_DATA:
996 : case WqeType::WQE_TYPE_DATA_NOTIFY:
997 : case WqeType::WQE_TYPE_ACK_NOTIFY:
998 : case WqeType::WQE_TYPE_DATA_ACK_NOTIFY:
999 : case WqeType::WQE_TYPE_DATA_WITH_NOTIFY:
1000 0 : wqeInfoTmp.wqeData.op = RA_WR_RDMA_WRITE;
1001 0 : wqeInfoTmp.wqeType = static_cast<u64>(wqeType);
1002 0 : break;
1003 0 : case WqeType::WQE_TYPE_DATA_WITH_REDUCE:
1004 0 : wqeInfoTmp.wqeData.op = RA_WR_RDMA_REDUCE_WRITE;
1005 0 : wqeInfoTmp.wqeData.aux = aux;
1006 : // REDUCE WRITE 作为特殊的DATA
1007 0 : wqeInfoTmp.wqeType = static_cast<u64>(WqeType::WQE_TYPE_DATA);
1008 0 : break;
1009 1 : case WqeType::WQE_TYPE_READ_DATA:
1010 1 : wqeInfoTmp.wqeData.op = RA_WR_RDMA_READ;
1011 1 : wqeInfoTmp.wqeType = static_cast<u64>(wqeType);
1012 1 : break;
1013 0 : default:
1014 0 : HCCL_ERROR("error wqeType[%d]", wqeType);
1015 0 : return HCCL_E_INTERNAL;
1016 : }
1017 1 : CHK_RET(GetWqeDataOffsetAndNotifyId(wqeType, wqeInfoTmp.wqeDataOffset, wqeInfoTmp.notifyId));
1018 :
1019 1 : wqeInfoVec.push_back(wqeInfoTmp);
1020 1 : return HCCL_SUCCESS;
1021 : }
1022 :
1023 0 : HcclResult TransportIbverbs::ConstructPayLoadWqe(
1024 : void* dstMemPtr, const void* src, u64 len, WqeType wqeType, WrAuxInfo& aux, std::vector<WqeInfo>& wqeInfoVec,
1025 : u32 txSendDataTimes)
1026 : {
1027 : HcclResult ret;
1028 : // 发送数据Wqe
1029 0 : for (u32 txSendDataIdx = 0; txSendDataIdx < txSendDataTimes; txSendDataIdx++) {
1030 0 : u64 txSendDataOffset = txSendDataIdx * RDMA_SEND_MAX_SIZE;
1031 0 : u64 txSendDataSize = (txSendDataIdx == (txSendDataTimes - 1)) ? len - txSendDataOffset : RDMA_SEND_MAX_SIZE;
1032 :
1033 0 : void* txdstMemPtr = reinterpret_cast<void*>(reinterpret_cast<char*>(dstMemPtr) + txSendDataOffset);
1034 :
1035 0 : const void* txsrcMemPtr = reinterpret_cast<const void*>(reinterpret_cast<const char*>(src) + txSendDataOffset);
1036 0 : ret = AddWqeList(txdstMemPtr, txsrcMemPtr, txSendDataSize, wqeType, aux, wqeInfoVec);
1037 0 : CHK_PRT_RET(
1038 : ret != HCCL_SUCCESS,
1039 : HCCL_ERROR(
1040 : "[TransportIbverbs][TxAsync]errNo[0x%016llx] In lbv exp, add wqe list failed."
1041 : "srcMemSize[%llu Byte]",
1042 : HCCL_ERROR_CODE(ret), txSendDataSize),
1043 : ret);
1044 : }
1045 :
1046 0 : return HCCL_SUCCESS;
1047 : }
1048 :
1049 0 : HcclResult TransportIbverbs::TxPayLoad(
1050 : UserMemType dstMemType, u64 dstOffset, const void* src, u64 len, WqeType wqeType, WrAuxInfo& aux,
1051 : std::vector<WqeInfo>& wqeInfoVec)
1052 : {
1053 0 : void* dstMemPtr = nullptr;
1054 0 : u64 dstMemSize = 0;
1055 : // 为保证单算子下不同数据量下子图的结构相同,zero byte message 时也需要下发task
1056 0 : u32 txSendDataTimes = (len == 0) ? 1 : (len + RDMA_SEND_MAX_SIZE - 1) / RDMA_SEND_MAX_SIZE;
1057 0 : CHK_RET(GetMemInfo(dstMemType, &dstMemPtr, &dstMemSize));
1058 :
1059 0 : if (dstOffset > dstMemSize) {
1060 0 : HCCL_ERROR(
1061 : "[TransportIbverbs][TxAsync]dst_mem_type=%d, dst_mem_ptr=%p, dst_offset=%llu, dst_mem_size=%llu Byte",
1062 : dstMemType, dstMemPtr, dstOffset, dstMemSize);
1063 0 : return HCCL_E_INTERNAL;
1064 : }
1065 :
1066 0 : dstMemPtr = reinterpret_cast<void*>(reinterpret_cast<char*>(dstMemPtr) + dstOffset);
1067 0 : CHK_RET(ConstructPayLoadWqe(dstMemPtr, src, len, wqeType, aux, wqeInfoVec, txSendDataTimes));
1068 :
1069 0 : return HCCL_SUCCESS;
1070 : }
1071 :
1072 0 : HcclResult TransportIbverbs::TxAsync(UserMemType dstMemType, u64 dstOffset, const void* src, u64 len, Stream& stream)
1073 : {
1074 0 : std::vector<WqeInfo> wqeInfoVec;
1075 0 : wqeInfoVec.reserve(WQE_RESERVE_LENGTH);
1076 0 : struct WrAuxInfo aux = {};
1077 0 : HCCL_DEBUG("TX src[%p] len[%llu] dstOffset[%llu]", src, len, dstOffset);
1078 :
1079 0 : if (src != nullptr) {
1080 0 : CHK_RET(TxPayLoad(dstMemType, dstOffset, src, len, WqeType::WQE_TYPE_DATA, aux, wqeInfoVec));
1081 : }
1082 :
1083 0 : CHK_RET(TxSendDataAndNotify(wqeInfoVec, stream, GetUseOneDoorbellValue()));
1084 0 : return HCCL_SUCCESS;
1085 0 : }
1086 :
1087 0 : HcclResult TransportIbverbs::TxWithReduce(
1088 : UserMemType dstMemType, u64 dstOffset, const void* src, u64 len, const HcclDataType datatype, HcclReduceOp redOp,
1089 : Stream& stream)
1090 : {
1091 0 : std::vector<WqeInfo> wqeInfoVec;
1092 0 : wqeInfoVec.reserve(WQE_RESERVE_LENGTH);
1093 0 : struct WrAuxInfo aux = {};
1094 0 : aux.dataType = RDMA_REDUCE_DATA_TYPE_TABLE[datatype];
1095 0 : aux.reduceType = RDMA_REDUCE_OP_TYPE_TABLE[redOp];
1096 0 : if (aux.dataType == static_cast<uint8_t>(RdmaReduceDataType::RDMA_REDUCE_DATA_INVALID)
1097 0 : || aux.reduceType == static_cast<uint8_t>(RdmaReduceOpType::RDMA_REDUCE_OP_INVALID)) {
1098 0 : HCCL_ERROR(
1099 : "unsupported data type [%s] or Reduce type [%s]", GetDataTypeEnumStr(datatype).c_str(),
1100 : GetReduceOpEnumStr(redOp).c_str());
1101 0 : return HCCL_E_INTERNAL;
1102 : }
1103 :
1104 0 : CHK_PTR_NULL(src);
1105 0 : CHK_RET(TxPayLoad(dstMemType, dstOffset, src, len, WqeType::WQE_TYPE_DATA_WITH_REDUCE, aux, wqeInfoVec));
1106 :
1107 0 : CHK_RET(TxSendDataAndNotify(wqeInfoVec, stream, GetUseOneDoorbellValue()));
1108 0 : return HCCL_SUCCESS;
1109 0 : }
1110 :
1111 0 : HcclResult TransportIbverbs::TxWithReduce(
1112 : const std::vector<TxMemoryInfo>& txWithReduceMems, const HcclDataType datatype, HcclReduceOp redOp, Stream& stream)
1113 : {
1114 0 : std::vector<WqeInfo> wqeInfoVec;
1115 0 : wqeInfoVec.reserve(WQE_RESERVE_LENGTH);
1116 0 : struct WrAuxInfo aux = {};
1117 0 : aux.dataType = RDMA_REDUCE_DATA_TYPE_TABLE[datatype];
1118 0 : aux.reduceType = RDMA_REDUCE_OP_TYPE_TABLE[redOp];
1119 0 : if (aux.dataType == static_cast<uint8_t>(RdmaReduceDataType::RDMA_REDUCE_DATA_INVALID)
1120 0 : || aux.reduceType == static_cast<uint8_t>(RdmaReduceOpType::RDMA_REDUCE_OP_INVALID)) {
1121 0 : HCCL_ERROR(
1122 : "unsupported data type [%s] or Reduce type [%s]", GetDataTypeEnumStr(datatype).c_str(),
1123 : GetReduceOpEnumStr(redOp).c_str());
1124 0 : return HCCL_E_INTERNAL;
1125 : }
1126 :
1127 0 : for (const TxMemoryInfo& txWithReduceMem : txWithReduceMems) {
1128 0 : CHK_RET(TxPayLoad(
1129 : txWithReduceMem.dstMemType, txWithReduceMem.dstOffset, txWithReduceMem.src, txWithReduceMem.len,
1130 : WqeType::WQE_TYPE_DATA_WITH_REDUCE, aux, wqeInfoVec));
1131 : }
1132 :
1133 0 : CHK_RET(TxSendDataAndNotify(wqeInfoVec, stream, GetUseOneDoorbellValue()));
1134 0 : return HCCL_SUCCESS;
1135 0 : }
1136 :
1137 0 : bool TransportIbverbs::IsSupportTransportWithReduce()
1138 : {
1139 0 : if (machinePara_.deviceType == DevType::DEV_TYPE_910B || machinePara_.deviceType == DevType::DEV_TYPE_910_93) {
1140 0 : return true;
1141 : } else {
1142 0 : return false;
1143 : }
1144 : }
1145 :
1146 : // 910A1 不支持write with notify;
1147 : // 910A2 由于PCIE through 和 write with notify 冲突,所以不支持write with Notify;
1148 0 : bool TransportIbverbs::IsSupportRdmaNotify() { return false; }
1149 :
1150 1 : bool TransportIbverbs::IsTemplateMode()
1151 : {
1152 1 : if (workFlowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE
1153 1 : || machinePara_.deviceType == DevType::DEV_TYPE_910B || machinePara_.deviceType == DevType::DEV_TYPE_910_93) {
1154 0 : return false;
1155 : } else {
1156 1 : return true;
1157 : }
1158 : }
1159 :
1160 0 : HcclResult TransportIbverbs::GetIndOpRemoteMemDetails(MemDetails** remoteMem, uint32_t* memNum, HcclMemType memType)
1161 : {
1162 0 : CHK_PRT_RET(remoteMem == nullptr, HCCL_ERROR("[%s] remoteMem is nullptr", __func__), HCCL_E_PARA);
1163 0 : CHK_PRT_RET(memNum == nullptr, HCCL_ERROR("[%s] memNum is nullptr", __func__), HCCL_E_PARA);
1164 :
1165 0 : *remoteMem = nullptr;
1166 0 : *memNum = 0;
1167 : uint32_t memCount;
1168 0 : if (memType == HcclMemType::HCCL_MEM_TYPE_DEVICE) {
1169 0 : memCount = remoteUserDeviceMemMsg_.size();
1170 0 : } else if (memType == HcclMemType::HCCL_MEM_TYPE_HOST) {
1171 0 : memCount = remoteUserHostMemMsg_.size();
1172 : } else {
1173 0 : HCCL_ERROR("[%s] not support memType[%d]", __func__, memType);
1174 0 : return HCCL_E_INTERNAL;
1175 : }
1176 0 : if (memCount == 0) {
1177 0 : HCCL_DEBUG("[%s] No remote memory regions available", __func__);
1178 0 : return HCCL_SUCCESS;
1179 : }
1180 : // 外部需要手动释放内存
1181 0 : MemDetails* remoteMemDetails = static_cast<MemDetails*>(malloc(memCount * sizeof(MemDetails)));
1182 0 : CHK_PTR_NULL(remoteMemDetails);
1183 0 : uint32_t index = 0;
1184 0 : if (memType == HcclMemType::HCCL_MEM_TYPE_DEVICE) {
1185 0 : for (const auto& msg : remoteUserDeviceMemMsg_) {
1186 0 : remoteMemDetails[index].addr = reinterpret_cast<u64>(msg.addr);
1187 0 : remoteMemDetails[index].size = msg.len;
1188 0 : remoteMemDetails[index].key = msg.lkey;
1189 0 : index++;
1190 : }
1191 0 : } else if (memType == HcclMemType::HCCL_MEM_TYPE_HOST) {
1192 0 : for (const auto& msg : remoteUserHostMemMsg_) {
1193 0 : remoteMemDetails[index].addr = reinterpret_cast<u64>(msg.addr);
1194 0 : remoteMemDetails[index].size = msg.len;
1195 0 : remoteMemDetails[index].key = msg.lkey;
1196 0 : index++;
1197 : }
1198 : }
1199 0 : *memNum = memCount;
1200 0 : *remoteMem = remoteMemDetails;
1201 :
1202 0 : HCCL_DEBUG("[%s] Successfully returned %u remote memory regions", __func__, index);
1203 0 : return HCCL_SUCCESS;
1204 : }
1205 :
1206 0 : HcclResult TransportIbverbs::GetIndOpRemoteMem(HcclMem** remoteMem, uint32_t* memNum)
1207 : {
1208 0 : CHK_PRT_RET(remoteMem == nullptr, HCCL_ERROR("[GetIndOpRemoteMem] remoteMem is nullptr"), HCCL_E_PARA);
1209 0 : CHK_PRT_RET(memNum == nullptr, HCCL_ERROR("[GetIndOpRemoteMem] memNum is nullptr"), HCCL_E_PARA);
1210 :
1211 0 : *remoteMem = nullptr;
1212 0 : *memNum = 0;
1213 :
1214 0 : std::lock_guard<std::mutex> lock(remoteMemsMutex_);
1215 :
1216 0 : if (!remoteMemsPtr_) {
1217 0 : uint32_t totalCount = remoteUserDeviceMemMsg_.size() + remoteUserHostMemMsg_.size();
1218 0 : if (totalCount == 0) {
1219 0 : HCCL_INFO("[GetIndOpRemoteMem] No remote memory regions available");
1220 0 : return HCCL_SUCCESS;
1221 : }
1222 0 : remoteMemsPtr_ = std::make_unique<HcclMem[]>(totalCount);
1223 0 : CHK_PTR_NULL(remoteMemsPtr_);
1224 0 : uint32_t index = 0;
1225 0 : for (const auto& msg : remoteUserDeviceMemMsg_) {
1226 0 : remoteMemsPtr_[index].type = HcclMemType::HCCL_MEM_TYPE_DEVICE;
1227 0 : remoteMemsPtr_[index].addr = msg.addr;
1228 0 : remoteMemsPtr_[index].size = msg.len;
1229 0 : index++;
1230 : }
1231 0 : for (const auto& msg : remoteUserHostMemMsg_) {
1232 0 : remoteMemsPtr_[index].type = HcclMemType::HCCL_MEM_TYPE_HOST;
1233 0 : remoteMemsPtr_[index].addr = msg.addr;
1234 0 : remoteMemsPtr_[index].size = msg.len;
1235 0 : index++;
1236 : }
1237 0 : remoteMemsNum_ = totalCount;
1238 : }
1239 :
1240 0 : *memNum = remoteMemsNum_;
1241 0 : *remoteMem = remoteMemsPtr_.get();
1242 :
1243 0 : return HCCL_SUCCESS;
1244 0 : }
1245 :
1246 0 : HcclResult TransportIbverbs::GetRemoteMem(UserMemType memType, void** remotePtr)
1247 : {
1248 0 : switch (memType) {
1249 0 : case UserMemType::INPUT_MEM:
1250 : case UserMemType::OUTPUT_MEM:
1251 0 : *remotePtr = remoteMemMsg_[static_cast<u32>(memType)].addr;
1252 0 : break;
1253 :
1254 0 : default:
1255 0 : HCCL_ERROR("[Get][RemoteMem]not support dst_mem_type=%d", memType);
1256 0 : return HCCL_E_NOT_SUPPORT;
1257 : }
1258 0 : return HCCL_SUCCESS;
1259 : }
1260 :
1261 0 : HcclResult TransportIbverbs::GetRemoteMemSize(UserMemType memType, u64& size)
1262 : {
1263 0 : switch (memType) {
1264 0 : case UserMemType::INPUT_MEM:
1265 : case UserMemType::OUTPUT_MEM:
1266 0 : size = remoteMemMsg_[static_cast<u32>(memType)].len;
1267 0 : break;
1268 :
1269 0 : default:
1270 0 : HCCL_ERROR("[Get][RemoteMem]not support dst_mem_type=%d", memType);
1271 0 : return HCCL_E_NOT_SUPPORT;
1272 : }
1273 0 : return HCCL_SUCCESS;
1274 : }
1275 :
1276 : HcclResult
1277 0 : TransportIbverbs::TxSendDataAndNotifyWithSingleQP(std::vector<WqeInfo>& wqeInfoVec, Stream& stream, bool useOneDoorbell)
1278 : {
1279 0 : if (IsSupportRdmaNotify() && wqeInfoVec.size() > 0) {
1280 : // 支持RDMA NOTIFY时, 修改wqeInfoVec中最后一个wqe, 使其附带Notify信息
1281 0 : u32 offset = static_cast<u32>(remoteDataNotifyMsg_.offset);
1282 0 : if (wqeInfoVec.back().wqeData.op == RA_WR_RDMA_REDUCE_WRITE) {
1283 0 : wqeInfoVec.back().wqeData.op = RA_WR_RDMA_REDUCE_WRITE_WITH_NOTIFY;
1284 : } else {
1285 0 : wqeInfoVec.back().wqeData.op = RA_WR_RDMA_WRITE_WITH_NOTIFY;
1286 : }
1287 0 : wqeInfoVec.back().wqeData.aux.notifyOffset = offset;
1288 : } else {
1289 : // 发送data notify同步信息
1290 0 : struct WrAuxInfo aux = {};
1291 0 : void* remoteNotifyaddr = remoteDataNotifyMsg_.addr;
1292 0 : CHK_RET(AddWqeList(
1293 : remoteNotifyaddr, notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_,
1294 : WqeType::WQE_TYPE_DATA_NOTIFY, aux, wqeInfoVec));
1295 : }
1296 :
1297 0 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE) {
1298 0 : CHK_RET(RdmaSendAsync(wqeInfoVec, stream, useOneDoorbell));
1299 : } else {
1300 0 : CHK_RET(RdmaSendAsyncHostNIC(wqeInfoVec, stream));
1301 : }
1302 0 : return HCCL_SUCCESS;
1303 : }
1304 :
1305 0 : u32 TransportIbverbs::GetActualQpNum(u32 maxLength)
1306 : {
1307 0 : u32 actualMultiQpNum = 1;
1308 0 : const u32 KByteToByte = 1024; // 1024 多QP阈值单位是KB
1309 0 : if (maxLength / qpsPerConnection_ >= GetExternalInputMultiQpThreshold() * KByteToByte) {
1310 0 : actualMultiQpNum = qpsPerConnection_;
1311 : } else {
1312 0 : u32 quotient = maxLength / (GetExternalInputMultiQpThreshold() * KByteToByte);
1313 0 : u32 remainder = maxLength % (GetExternalInputMultiQpThreshold() * KByteToByte);
1314 0 : actualMultiQpNum = quotient + (remainder != 0 ? 1 : 0);
1315 : }
1316 :
1317 0 : return actualMultiQpNum;
1318 : }
1319 :
1320 0 : HcclResult TransportIbverbs::TxSendDataAndNotify(std::vector<WqeInfo>& wqeInfoVec, Stream& stream, bool useOneDoorbell)
1321 : {
1322 0 : u32 maxLength = 0;
1323 0 : for (u32 i = 0; i < wqeInfoVec.size(); i++) {
1324 0 : if (wqeInfoVec[i].wqeData.memList.len > maxLength) {
1325 0 : maxLength = wqeInfoVec[i].wqeData.memList.len;
1326 : }
1327 : }
1328 :
1329 0 : u32 actualMultiQpNum = GetActualQpNum(maxLength);
1330 :
1331 0 : HCCL_DEBUG(
1332 : "[TransportIbverbs][TxSendDataAndNotify] UseMultiQp[%d] MultiQpNum[%u] actualMultiQpNum[%u] maxLength[%u]",
1333 : UseMultiQp(), qpsPerConnection_, actualMultiQpNum, maxLength);
1334 0 : if (UseMultiQp() && actualMultiQpNum != 1 && actualMultiQpNum <= qpsPerConnection_ && maxLength != 0) {
1335 0 : CHK_RET(TxSendDataAndNotifyWithMultiQP(wqeInfoVec, actualMultiQpNum, stream, useOneDoorbell));
1336 : } else {
1337 0 : CHK_RET(TxSendDataAndNotifyWithSingleQP(wqeInfoVec, stream, useOneDoorbell));
1338 : }
1339 0 : return HCCL_SUCCESS;
1340 : }
1341 :
1342 0 : std::vector<u32> TransportIbverbs::RdmaLengthSplit(u32 length, u32 splitNum)
1343 : {
1344 : // step 1, 先计算有多少个128 Byte
1345 0 : u32 alignNum = length / RDMA_ADDR_ALIGNMENT;
1346 0 : u32 tailBytes = length % RDMA_ADDR_ALIGNMENT; // 尾块简单处理,放在最后一个切分出来的块后面
1347 : // step 2, 将这128 Byte再分成 splitNum 分,每一份有多少个 128Byte
1348 0 : u32 alignNumPerSplit = alignNum / splitNum;
1349 0 : u32 tailAlignNum = alignNum % splitNum; // 尾块简单处理,放在最后一个切分出来的块后面
1350 0 : std::vector<u32> vctSplittedLength(splitNum, 0);
1351 0 : for (u32 i = 0; i < splitNum; i++) {
1352 0 : u32 lengthTmp = alignNumPerSplit * RDMA_ADDR_ALIGNMENT;
1353 0 : vctSplittedLength[i] = lengthTmp;
1354 : }
1355 0 : vctSplittedLength[splitNum - 1] += tailAlignNum * RDMA_ADDR_ALIGNMENT + tailBytes;
1356 0 : return vctSplittedLength;
1357 : }
1358 :
1359 0 : HcclResult TransportIbverbs::TxSendDataAndNotifyWithMultiQP(
1360 : std::vector<WqeInfo>& wqeInfoVec, u32 actualMultiQpNum, Stream& stream, [[maybe_unused]] bool useOneDoorbell)
1361 : {
1362 : // vector<WqeInfo> 是一个vector的原因是 单个wqe只能发2GB数据,如果超过2GB,就拆分到多个WqeInfo中了
1363 : // 多QP下,对每个WqeInfo都进行多QP切分,然后在收发每一个QP的数据
1364 0 : std::vector<std::vector<WqeInfo>> multiQpWqeInfoVct(actualMultiQpNum, wqeInfoVec);
1365 0 : for (u32 i = 0; i < wqeInfoVec.size(); i++) {
1366 0 : WqeInfo tmpWqeInfo = wqeInfoVec[i];
1367 0 : u32 curLen = tmpWqeInfo.wqeData.memList.len;
1368 0 : std::vector<u32> splittedLen = RdmaLengthSplit(curLen, actualMultiQpNum);
1369 0 : uint64_t curSrcAddr = tmpWqeInfo.wqeData.memList.addr;
1370 0 : uint64_t curDstAddr = tmpWqeInfo.wqeData.dstAddr;
1371 0 : for (u32 qpIndex = 0; qpIndex < actualMultiQpNum; qpIndex++) {
1372 0 : multiQpWqeInfoVct[qpIndex][i].wqeData.memList.len = splittedLen[qpIndex];
1373 0 : multiQpWqeInfoVct[qpIndex][i].wqeData.memList.addr = curSrcAddr;
1374 0 : multiQpWqeInfoVct[qpIndex][i].wqeData.dstAddr = curDstAddr;
1375 0 : curSrcAddr += splittedLen[qpIndex];
1376 0 : curDstAddr += splittedLen[qpIndex];
1377 : }
1378 0 : }
1379 : // 给每个QP最后增加一个属于该QP的DataNotify
1380 0 : for (u32 qpIndex = 0; qpIndex < actualMultiQpNum; qpIndex++) {
1381 0 : struct WrAuxInfo aux = {};
1382 0 : void* remoteNotifyaddr = multiQpDataNotifyRemoteMemMsg_[qpIndex].addr;
1383 0 : CHK_RET(AddWqeList(
1384 : remoteNotifyaddr, notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_,
1385 : WqeType::WQE_TYPE_DATA_NOTIFY, aux, multiQpWqeInfoVct[qpIndex]));
1386 : }
1387 : // useOneDoorbell 配置成true。最后一个payload去按doorbell
1388 0 : for (u32 qpIndex = 0; qpIndex < actualMultiQpNum; qpIndex++) {
1389 0 : CHK_RET(
1390 : RdmaSendAsync(multiQpWqeInfoVct[qpIndex], stream, true, qpIndex)); // 多QP使用同一个stream异步doorbell触发
1391 : }
1392 0 : return HCCL_SUCCESS;
1393 0 : }
1394 :
1395 0 : HcclResult TransportIbverbs::TxAsync(std::vector<TxMemoryInfo>& txMems, Stream& stream)
1396 : {
1397 0 : std::vector<WqeInfo> wqeInfoVec;
1398 0 : wqeInfoVec.reserve(WQE_RESERVE_LENGTH);
1399 0 : struct WrAuxInfo aux = {};
1400 :
1401 0 : for (auto& mem : txMems) {
1402 0 : HCCL_DEBUG("TX src[%p] len[%llu] dstOffset[%llu]", mem.src, mem.len, mem.dstOffset);
1403 0 : CHK_PTR_NULL(mem.src);
1404 0 : CHK_RET(TxPayLoad(mem.dstMemType, mem.dstOffset, mem.src, mem.len, WqeType::WQE_TYPE_DATA, aux, wqeInfoVec));
1405 : }
1406 :
1407 0 : CHK_RET(TxSendDataAndNotify(wqeInfoVec, stream, GetUseOneDoorbellValue()));
1408 0 : return HCCL_SUCCESS;
1409 0 : }
1410 :
1411 1 : HcclResult TransportIbverbs::TxWqeList(
1412 : std::vector<WqeInfo>& wqeInfoVec, Stream& stream, std::vector<struct SendWrRsp>& opRspVec, u32 multiQpIndex)
1413 : {
1414 : (void)stream;
1415 1 : if (!IsTemplateMode()) {
1416 0 : currentQP_ = 0;
1417 : } else {
1418 2 : if (sqeCounter_ < (HCCP_SQ_TEMPLATE_CAPACITY + 1)
1419 1 : && (sqeCounter_ + wqeInfoVec.size()) >= (HCCP_SQ_TEMPLATE_CAPACITY + 1)) {
1420 0 : currentQP_++;
1421 0 : sqeCounter_ = wqeInfoVec.size();
1422 : } else {
1423 1 : sqeCounter_ += wqeInfoVec.size();
1424 : }
1425 : }
1426 1 : CHK_PRT_RET(
1427 : currentQP_ >= combineQpHandles_.size(),
1428 : HCCL_ERROR(
1429 : "[TransportIbverbs][TxWqeList]errNo[0x%016llx] In lbv "
1430 : "exp, qp idx[%u] is invalid.",
1431 : HCCL_ERROR_CODE(HCCL_E_INTERNAL), currentQP_),
1432 : HCCL_E_INTERNAL);
1433 :
1434 0 : HCCL_DEBUG("rdma tx send wqes: ra qp sqe counter:%u, current qp idx:%u", sqeCounter_, currentQP_);
1435 :
1436 0 : std::vector<SendWrlistDataExt> wqelisDatatVec;
1437 0 : for (u32 index = 0; index < wqeInfoVec.size(); index++) {
1438 : // 使能atomic write场景下,reduce的下一个notify的opcode要设置为atomic write
1439 0 : u32& preWrOpcode = multiQpIndex == RDMA_INVALID_QP_INDEX ? combineQpHandles_[currentQP_].preWrOpcode :
1440 0 : multiCombineQpHandles_[multiQpIndex].preWrOpcode;
1441 0 : ModifyAtomicWriteAfterReduce(
1442 0 : preWrOpcode, wqeInfoVec[index].wqeType, wqeInfoVec[index].wqeData.op,
1443 0 : wqeInfoVec[index].wqeData.ext.immData);
1444 :
1445 0 : wqelisDatatVec.push_back(wqeInfoVec[index].wqeData);
1446 : }
1447 :
1448 0 : u32 totalWqeCount = wqelisDatatVec.size();
1449 0 : struct SendWrlistDataExt* wqelist = wqelisDatatVec.data();
1450 0 : struct SendWrRsp* opRsp = opRspVec.data();
1451 :
1452 : // HCCP会校验 zero byte messages 的内存地址是否已注册MR。对于 zero byte messages 不下发WR,将opRsp设置为特殊值。
1453 : // 下发rdmasend task时检查该特殊值,如果zero byte message则不下发rdmasend task。
1454 0 : bool batchSendWr = true;
1455 0 : for (u32 i = 0; i < totalWqeCount; i++) {
1456 0 : if (wqelisDatatVec[i].memList.len == 0) {
1457 0 : batchSendWr = false;
1458 0 : break;
1459 : }
1460 : }
1461 : QpHandle currentQp;
1462 0 : if (multiQpIndex == RDMA_INVALID_QP_INDEX) {
1463 0 : currentQp = combineQpHandles_[currentQP_].qpHandle;
1464 : } else {
1465 0 : currentQp = multiCombineQpHandles_[multiQpIndex].qpHandle;
1466 : }
1467 0 : if (batchSendWr) {
1468 0 : CHK_RET(SendWqeList(currentQp, totalWqeCount, wqelist, opRsp));
1469 : } else {
1470 0 : for (u32 i = 0; i < totalWqeCount; i++) {
1471 0 : if (wqelisDatatVec[i].memList.len > 0) {
1472 0 : CHK_RET(SendWqeList(currentQp, 1U, &wqelist[i], &opRsp[i]));
1473 : } else {
1474 0 : opRsp[i].wqeTmp.sqIndex = INVALID_UINT;
1475 0 : opRsp[i].wqeTmp.wqeIndex = INVALID_UINT;
1476 0 : opRsp[i].db.dbIndex = INVALID_UINT;
1477 0 : opRsp[i].db.dbInfo = INVALID_U64;
1478 : }
1479 : }
1480 : }
1481 :
1482 0 : return HCCL_SUCCESS;
1483 0 : }
1484 :
1485 : HcclResult
1486 0 : TransportIbverbs::SendWqeList(QpHandle qpHandle, u32 wqeNum, struct SendWrlistDataExt* wqelist, struct SendWrRsp* opRsp)
1487 : {
1488 0 : unsigned int completeNum = 0;
1489 0 : HcclResult ret = HrtRaSendWrlistExt(qpHandle, wqelist, opRsp, wqeNum, &completeNum);
1490 0 : CHK_PRT_RET(
1491 : ret != HCCL_SUCCESS,
1492 : HCCL_ERROR("[TransportIbverbs][TxWqeList]In ibv send wq list, HrtRaSendWrlist failed.ret[%d]", ret),
1493 : HCCL_E_NETWORK);
1494 0 : return HCCL_SUCCESS;
1495 : }
1496 :
1497 : HcclResult
1498 1 : TransportIbverbs::RdmaSendAsync(std::vector<WqeInfo>& wqeInfoVec, Stream& stream, bool useOneDoorbell, u32 multiQpIndex)
1499 : {
1500 : HcclResult ret;
1501 :
1502 1 : std::vector<struct SendWrRsp> opRspVec(wqeInfoVec.size());
1503 1 : CHK_RET(TxWqeList(wqeInfoVec, stream, opRspVec, multiQpIndex));
1504 :
1505 0 : std::vector<SendWrlistDataExt> wqelistVec;
1506 0 : for (u32 index = 0; index < wqeInfoVec.size(); index++) {
1507 0 : wqelistVec.push_back(wqeInfoVec[index].wqeData);
1508 : }
1509 :
1510 0 : struct SendWr wr = {};
1511 0 : wr.bufNum = 1;
1512 0 : wr.op = 0;
1513 0 : wr.sendFlag = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
1514 0 : fence_ = false;
1515 :
1516 0 : if (useOneDoorbell && !IsTemplateMode()) {
1517 : // 内存块不连续时,只敲最后一次doorbell
1518 0 : wr.bufList = &wqelistVec.back().memList;
1519 0 : wr.dstAddr = static_cast<u64>(wqelistVec.back().dstAddr);
1520 : // 只敲一次doorbell时,len为所有非连续内存块长度总和+notify(4Bytes)
1521 0 : wr.bufList[0].len = std::accumulate(wqelistVec.begin(), wqelistVec.end(), 0llu, [](u64 acc, auto wqelist) {
1522 0 : return acc + wqelist.memList.len;
1523 : });
1524 :
1525 0 : const u32 dbIndex = static_cast<u32>(opRspVec.back().db.dbIndex);
1526 0 : const u64 dbInfo = static_cast<u64>(opRspVec.back().db.dbInfo);
1527 0 : ret = dispatcher_->RdmaSend(dbIndex, dbInfo, wr, stream, machinePara_.remoteWorldRank, isCapture_);
1528 0 : CHK_PRT_RET(
1529 : ret != HCCL_SUCCESS,
1530 : HCCL_ERROR(
1531 : "[TransportIbverbs][RdmaSendAsync][useOneDoorbell]errNo[0x%016llx] In lbv exp op base mode, "
1532 : "rdma send failed. dbIndex[%u] dbInfo[%llu]",
1533 : HCCL_ERROR_CODE(ret), dbIndex, dbInfo),
1534 : ret);
1535 0 : HCCL_INFO("[TransportIbverbs][RdmaSendAsync][useOneDoorbell] db_index[%u], db_info[%llu]", dbIndex, dbInfo);
1536 0 : return HCCL_SUCCESS;
1537 : }
1538 :
1539 0 : for (u32 i = 0; i < wqeInfoVec.size(); i++) {
1540 0 : wr.bufList = &wqelistVec[i].memList;
1541 0 : wr.dstAddr = static_cast<u64>(wqelistVec[i].dstAddr);
1542 :
1543 0 : if (!IsTemplateMode()) {
1544 0 : u32 dbIndex = static_cast<u32>(opRspVec[i].db.dbIndex);
1545 0 : u64 dbInfo = static_cast<u64>(opRspVec[i].db.dbInfo);
1546 :
1547 : // op base 模式下的发送接口
1548 0 : if (wqeInfoVec[i].wqeType == static_cast<u64>(WqeType::WQE_TYPE_DATA)) {
1549 0 : ret = dispatcher_->RdmaSend(dbIndex, dbInfo, wr, stream, machinePara_.remoteWorldRank, isCapture_);
1550 : } else {
1551 0 : ret = dispatcher_->RdmaSend(
1552 0 : dbIndex, dbInfo, wr, stream, machinePara_.remoteWorldRank, wqeInfoVec[i].wqeDataOffset, isCapture_);
1553 : }
1554 0 : CHK_PRT_RET(
1555 : ret != HCCL_SUCCESS,
1556 : HCCL_ERROR(
1557 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In lbv exp op base mode, "
1558 : "rdma send failed. dbIndex[%u] dbInfo[%llu] wqe type[%llu] offset[%llu]",
1559 : HCCL_ERROR_CODE(ret), dbIndex, dbInfo, wqeInfoVec[i].wqeType, wqeInfoVec[i].wqeDataOffset),
1560 : ret);
1561 : } else { // offline mode
1562 : // 下沉模式
1563 0 : if (wqeInfoVec[i].wqeType == static_cast<u64>(WqeType::WQE_TYPE_DATA)) {
1564 0 : ret = dispatcher_->RdmaSend(
1565 0 : opRspVec[i].wqeTmp.sqIndex, opRspVec[i].wqeTmp.wqeIndex, wr, stream, machinePara_.remoteWorldRank);
1566 : } else {
1567 0 : ret = dispatcher_->RdmaSend(
1568 0 : opRspVec[i].wqeTmp.sqIndex, opRspVec[i].wqeTmp.wqeIndex, wr, stream, machinePara_.remoteWorldRank,
1569 0 : wqeInfoVec[i].wqeDataOffset);
1570 : }
1571 0 : CHK_PRT_RET(
1572 : ret != HCCL_SUCCESS,
1573 : HCCL_ERROR(
1574 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In lbv exp offline mode, "
1575 : "rdma send failed. sq_index[%u] wqe_index[%u], offset[%llu]",
1576 : HCCL_ERROR_CODE(ret), opRspVec[i].wqeTmp.sqIndex, opRspVec[i].wqeTmp.wqeIndex,
1577 : wqeInfoVec[i].wqeDataOffset),
1578 : ret);
1579 : }
1580 : }
1581 0 : return HCCL_SUCCESS;
1582 1 : }
1583 0 : HcclResult TransportIbverbs::RdmaSendAsyncHostNIC(std::vector<WqeInfo>& wqeInfoVec, Stream& stream)
1584 : {
1585 : HcclResult ret;
1586 :
1587 0 : std::vector<SendWrlistDataExt> wqelistVec;
1588 0 : for (u32 index = 0; index < wqeInfoVec.size(); index++) {
1589 0 : wqelistVec.push_back(wqeInfoVec[index].wqeData);
1590 : }
1591 0 : struct SendWrRsp opRsp = {};
1592 0 : struct SendWrlistDataExt wr = {};
1593 0 : for (u32 i = 0; i < wqeInfoVec.size(); i++) {
1594 0 : wr.memList.addr = wqelistVec[i].memList.addr;
1595 0 : wr.memList.len = wqelistVec[i].memList.len;
1596 0 : wr.dstAddr = static_cast<u64>(wqelistVec[i].dstAddr);
1597 0 : wr.op = 0;
1598 0 : wr.sendFlags = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
1599 0 : fence_ = false;
1600 :
1601 0 : if (wqeInfoVec[i].wqeType == static_cast<u64>(WqeType::WQE_TYPE_DATA)) {
1602 0 : ret = dispatcher_->HostNicRdmaSend(
1603 0 : combineQpHandles_[0].qpHandle, wr, opRsp, stream, machinePara_.remoteWorldRank);
1604 : } else {
1605 0 : ret = dispatcher_->HostNicRdmaSend(
1606 0 : combineQpHandles_[0].qpHandle, wr, opRsp, stream, machinePara_.remoteWorldRank,
1607 0 : wqeInfoVec[i].wqeDataOffset);
1608 : }
1609 0 : CHK_PRT_RET(
1610 : ret != HCCL_SUCCESS,
1611 : HCCL_ERROR(
1612 : "[TransportIbverbs][RdmaSendAsyncHostNIC]errNo[0x%016llx] In lbv exp offline "
1613 : "mode, rdma send failed. sq_index[%u] wqe_index[%u], offset[%llu]",
1614 : HCCL_ERROR_CODE(ret), opRsp.wqeTmp.sqIndex, opRsp.wqeTmp.wqeIndex, wqeInfoVec[i].wqeDataOffset),
1615 : ret);
1616 : }
1617 0 : return HCCL_SUCCESS;
1618 0 : }
1619 0 : HcclResult TransportIbverbs::RdmaSendAsync(
1620 : struct SendWr& wr, Stream& stream, WqeType wqeType, u64 notifyOffset, [[maybe_unused]] u32 notifyId)
1621 : {
1622 : HcclResult ret;
1623 0 : struct SendWrRsp opRsp = {};
1624 0 : if (!IsTemplateMode()) {
1625 0 : currentQP_ = 0;
1626 : } else {
1627 0 : if (sqeCounter_ == HCCP_SQ_TEMPLATE_CAPACITY) {
1628 0 : currentQP_++;
1629 0 : sqeCounter_ = 1;
1630 : } else {
1631 0 : sqeCounter_++;
1632 : }
1633 : }
1634 0 : CHK_PRT_RET(
1635 : currentQP_ >= combineQpHandles_.size(),
1636 : HCCL_ERROR(
1637 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In "
1638 : "lbv exp, qp idx[%u] is invalid.",
1639 : HCCL_ERROR_CODE(HCCL_E_INTERNAL), currentQP_),
1640 : HCCL_E_INTERNAL);
1641 0 : HCCL_DEBUG("rdma send async: ra qp sqe counter:%u, current qp idx:%u.", sqeCounter_, currentQP_);
1642 :
1643 0 : CHK_RET(HrtRaSendWr(combineQpHandles_[currentQP_].qpHandle, &wr, &opRsp));
1644 :
1645 0 : if (!IsTemplateMode()) {
1646 0 : u32 dbIndex = static_cast<u32>(opRsp.db.dbIndex);
1647 0 : u64 dbInfo = static_cast<u64>(opRsp.db.dbInfo);
1648 0 : if (wqeType == WqeType::WQE_TYPE_DATA) {
1649 0 : ret = dispatcher_->RdmaSend(dbIndex, dbInfo, wr, stream, machinePara_.remoteWorldRank, isCapture_);
1650 0 : CHK_PRT_RET(
1651 : ret != HCCL_SUCCESS,
1652 : HCCL_ERROR(
1653 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In lbv exp op base mode, "
1654 : "rdma send failed. dbIndex[%u] dbInfo[%llu]",
1655 : HCCL_ERROR_CODE(ret), dbIndex, dbInfo),
1656 : ret);
1657 : } else {
1658 0 : ret = dispatcher_->RdmaSend(
1659 0 : dbIndex, dbInfo, wr, stream, machinePara_.remoteWorldRank, notifyOffset, isCapture_);
1660 0 : CHK_PRT_RET(
1661 : ret != HCCL_SUCCESS,
1662 : HCCL_ERROR(
1663 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In lbv exp op base mode, "
1664 : "rdma send failed. dbIndex[%u] dbInfo[%llu], offset[%llu]",
1665 : HCCL_ERROR_CODE(ret), dbIndex, dbInfo, notifyOffset),
1666 : ret);
1667 : }
1668 : } else { // offline mode
1669 0 : if (wqeType == WqeType::WQE_TYPE_DATA) {
1670 0 : ret = dispatcher_->RdmaSend(
1671 : opRsp.wqeTmp.sqIndex, opRsp.wqeTmp.wqeIndex, wr, stream, machinePara_.remoteWorldRank);
1672 0 : CHK_PRT_RET(
1673 : ret != HCCL_SUCCESS,
1674 : HCCL_ERROR(
1675 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In lbv exp offline mode, "
1676 : "rdma send failed. sq_index[%u] wqe_index[%u]",
1677 : HCCL_ERROR_CODE(ret), opRsp.wqeTmp.sqIndex, opRsp.wqeTmp.wqeIndex),
1678 : ret);
1679 : } else {
1680 0 : ret = dispatcher_->RdmaSend(
1681 : opRsp.wqeTmp.sqIndex, opRsp.wqeTmp.wqeIndex, wr, stream, machinePara_.remoteWorldRank, notifyOffset);
1682 0 : CHK_PRT_RET(
1683 : ret != HCCL_SUCCESS,
1684 : HCCL_ERROR(
1685 : "[TransportIbverbs][RdmaSendAsync]errNo[0x%016llx] In lbv exp offline mode, "
1686 : "rdma send failed. sq_index[%u] wqe_index[%u], offset[%llu]",
1687 : HCCL_ERROR_CODE(ret), opRsp.wqeTmp.sqIndex, opRsp.wqeTmp.wqeIndex, notifyOffset),
1688 : ret);
1689 : }
1690 : }
1691 0 : return HCCL_SUCCESS;
1692 : }
1693 : HcclResult
1694 0 : TransportIbverbs::RdmaSendAsyncHostNIC(struct SendWrlistDataExt& wr, Stream& stream, WqeType wqeType, u64 notifyOffset)
1695 : {
1696 : HcclResult ret;
1697 0 : struct SendWrRsp opRsp = {};
1698 0 : if (wqeType == WqeType::WQE_TYPE_DATA) {
1699 0 : ret = dispatcher_->HostNicRdmaSend(
1700 0 : combineQpHandles_[0].qpHandle, wr, opRsp, stream, machinePara_.remoteWorldRank);
1701 : } else {
1702 0 : ret = dispatcher_->HostNicRdmaSend(
1703 0 : combineQpHandles_[0].qpHandle, wr, opRsp, stream, machinePara_.remoteWorldRank, notifyOffset);
1704 : }
1705 0 : CHK_PRT_RET(
1706 : ret != HCCL_SUCCESS,
1707 : HCCL_ERROR(
1708 : "[TransportIbverbs][RdmaSendAsyncHostNIC]errNo[0x%016llx] In lbv exp offline mode, "
1709 : "rdma send failed. sq_index[%u] wqe_index[%u], offset[%llu]",
1710 : HCCL_ERROR_CODE(ret), opRsp.wqeTmp.sqIndex, opRsp.wqeTmp.wqeIndex, notifyOffset),
1711 : ret);
1712 :
1713 0 : return HCCL_SUCCESS;
1714 : }
1715 1 : HcclResult TransportIbverbs::GetWqeDataOffsetAndNotifyId(WqeType wqeType, u64& wqeDataOffset, u32& notifyId)
1716 : {
1717 1 : switch (wqeType) {
1718 1 : case WqeType::WQE_TYPE_DATA:
1719 : case WqeType::WQE_TYPE_DATA_WITH_NOTIFY:
1720 : case WqeType::WQE_TYPE_DATA_WITH_REDUCE:
1721 : case WqeType::WQE_TYPE_READ_DATA:
1722 1 : wqeDataOffset = 0;
1723 1 : notifyId = INVALID_UINT;
1724 1 : break;
1725 0 : case WqeType::WQE_TYPE_DATA_NOTIFY:
1726 0 : wqeDataOffset = remoteDataNotifyMsg_.offset;
1727 0 : notifyId = remoteDataNotifyMsg_.notifyId;
1728 0 : break;
1729 0 : case WqeType::WQE_TYPE_ACK_NOTIFY:
1730 0 : wqeDataOffset = remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].offset;
1731 0 : notifyId = remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].notifyId;
1732 0 : break;
1733 0 : case WqeType::WQE_TYPE_DATA_ACK_NOTIFY:
1734 0 : wqeDataOffset = remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].offset;
1735 0 : notifyId = remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].notifyId;
1736 0 : break;
1737 0 : default:
1738 0 : HCCL_ERROR("[Get][WqeDataOffset]error wqeType[%d]", wqeType);
1739 0 : return HCCL_E_INTERNAL;
1740 : }
1741 1 : return HCCL_SUCCESS;
1742 : }
1743 :
1744 : HcclResult
1745 0 : TransportIbverbs::TxSendWqe(void* dstMemPtr, const void* srcMemPtr, u64 srcMemSize, Stream& stream, WqeType wqeType)
1746 : {
1747 0 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE && !useAtomicWrite_) {
1748 0 : struct SgList list = {};
1749 0 : struct SendWr wr = {};
1750 : // 构造wr信息
1751 0 : list.addr = static_cast<u64>(reinterpret_cast<uintptr_t>(srcMemPtr));
1752 0 : list.len = srcMemSize;
1753 :
1754 0 : wr.bufList = &list;
1755 0 : wr.bufNum = 1; /* 此处list只有一个,设置为1 */
1756 0 : wr.dstAddr = static_cast<u64>(reinterpret_cast<uintptr_t>(dstMemPtr));
1757 0 : wr.op = 0; /* RDMA_WRITE: 0 */
1758 0 : wr.sendFlag = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
1759 0 : fence_ = false;
1760 :
1761 : // 获取notify偏移地址,对于发送数据时,偏移地址为0
1762 0 : u32 notifyId = INVALID_UINT;
1763 0 : u64 wqeDataOffset = 0;
1764 0 : CHK_RET(GetWqeDataOffsetAndNotifyId(wqeType, wqeDataOffset, notifyId));
1765 :
1766 : // RDMA异步发送
1767 0 : CHK_RET(RdmaSendAsync(wr, stream, wqeType, wqeDataOffset, notifyId));
1768 0 : } else if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE && useAtomicWrite_) {
1769 0 : struct WrAuxInfo aux = {};
1770 0 : std::vector<WqeInfo> wqeInfoVec;
1771 0 : CHK_RET(AddWqeList(dstMemPtr, srcMemPtr, srcMemSize, wqeType, aux, wqeInfoVec));
1772 0 : CHK_RET(RdmaSendAsync(wqeInfoVec, stream, false));
1773 0 : HCCL_DEBUG("TxSendWqe useAtomicWrite[%d]", useAtomicWrite_);
1774 0 : } else {
1775 0 : struct SendWrlistDataExt wr = {};
1776 : // 构造wr信息
1777 0 : wr.memList.addr = static_cast<u64>(reinterpret_cast<uintptr_t>(srcMemPtr));
1778 0 : wr.memList.len = srcMemSize;
1779 :
1780 0 : wr.dstAddr = static_cast<u64>(reinterpret_cast<uintptr_t>(dstMemPtr));
1781 0 : wr.op = 0; /* RDMA_WRITE: 0 */
1782 0 : wr.sendFlags = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
1783 0 : fence_ = false;
1784 :
1785 : // 获取notify偏移地址,对于发送数据时,偏移地址为0
1786 0 : u32 notifyId = INVALID_UINT;
1787 0 : u64 wqeDataOffset = 0;
1788 0 : CHK_RET(GetWqeDataOffsetAndNotifyId(wqeType, wqeDataOffset, notifyId));
1789 :
1790 : // RDMA异步发送
1791 0 : CHK_RET(RdmaSendAsyncHostNIC(wr, stream, wqeType, wqeDataOffset));
1792 : }
1793 0 : return HCCL_SUCCESS;
1794 : }
1795 :
1796 0 : HcclResult TransportIbverbs::TxSendNotifyWqe(MemMsg& memMsg, const void* srcMemPtr, u64 srcMemSize, Stream& stream)
1797 : {
1798 0 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE && !useAtomicWrite_) {
1799 0 : struct SgList list = {};
1800 0 : struct SendWr wr = {};
1801 : // 构造wr信息
1802 0 : list.addr = static_cast<u64>(reinterpret_cast<uintptr_t>(srcMemPtr));
1803 0 : list.len = srcMemSize;
1804 0 : wr.bufList = &list;
1805 0 : wr.bufNum = 1; /* 此处list只有一个,设置为1 */
1806 0 : wr.dstAddr = static_cast<u64>(reinterpret_cast<uintptr_t>(memMsg.addr));
1807 0 : wr.op = 0; /* RDMA_WRITE: 0 */
1808 0 : wr.sendFlag = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
1809 0 : fence_ = false;
1810 :
1811 : // RDMA异步发送
1812 0 : CHK_RET(RdmaSendAsync(wr, stream, WqeType::WQE_TYPE_ACK_NOTIFY, memMsg.offset, memMsg.notifyId));
1813 0 : } else if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE && useAtomicWrite_) {
1814 0 : struct WrAuxInfo aux = {};
1815 0 : std::vector<WqeInfo> wqeInfoVec;
1816 0 : CHK_RET(AddWqeList(memMsg.addr, srcMemPtr, srcMemSize, WqeType::WQE_TYPE_ACK_NOTIFY, aux, wqeInfoVec));
1817 0 : CHK_RET(RdmaSendAsync(wqeInfoVec, stream, false));
1818 0 : HCCL_DEBUG("TxSendNotifyWqe useAtomicWrite[%d]", useAtomicWrite_);
1819 0 : } else {
1820 0 : struct SendWrlistDataExt wr = {};
1821 : // 构造wr信息
1822 0 : wr.memList.addr = static_cast<u64>(reinterpret_cast<uintptr_t>(srcMemPtr));
1823 0 : wr.memList.len = srcMemSize;
1824 0 : wr.dstAddr = static_cast<u64>(reinterpret_cast<uintptr_t>(memMsg.addr));
1825 0 : wr.op = 0; /* RDMA_WRITE: 0 */
1826 0 : wr.sendFlags = fence_ ? (RA_SEND_SIGNALED | RA_SEND_FENCE) : RA_SEND_SIGNALED;
1827 0 : fence_ = false;
1828 :
1829 : // RDMA异步发送
1830 0 : CHK_RET(RdmaSendAsyncHostNIC(wr, stream, WqeType::WQE_TYPE_ACK_NOTIFY, memMsg.offset));
1831 : }
1832 0 : return HCCL_SUCCESS;
1833 : }
1834 :
1835 : HcclResult
1836 0 : TransportIbverbs::RxAsync([[maybe_unused]] UserMemType srcMemType, u64 srcOffset, void* dst, u64 len, Stream& stream)
1837 : {
1838 0 : u32 actualMultiQpNum = 1;
1839 0 : const u32 KByteToByte = 1024; // 1024 多QP阈值单位是KB
1840 0 : if (len / qpsPerConnection_ > GetExternalInputMultiQpThreshold() * KByteToByte) {
1841 0 : actualMultiQpNum = qpsPerConnection_;
1842 : } else {
1843 0 : u32 quotient = len / (GetExternalInputMultiQpThreshold() * KByteToByte);
1844 0 : u32 remainder = len % (GetExternalInputMultiQpThreshold() * KByteToByte);
1845 0 : actualMultiQpNum = quotient + (remainder != 0 ? 1 : 0);
1846 : }
1847 : // 等待TS把任务处理完成
1848 0 : HCCL_DEBUG(
1849 : "[TransportIbverbs][RxAsync] UseMultiQp[%d] actualMultiQpNum[%u], RX dst[%p] len[%llu] srcOffset[%llu]",
1850 : UseMultiQp(), actualMultiQpNum, dst, len, srcOffset);
1851 0 : if (UseMultiQp() && actualMultiQpNum != 1 && actualMultiQpNum <= qpsPerConnection_ && len != 0) {
1852 0 : for (u32 i = 0; i < actualMultiQpNum; i++) {
1853 0 : CHK_RET(LocalIpcNotify::Wait(
1854 : stream, dispatcher_, multiQpDataNotify_[i], INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME,
1855 : machinePara_.localUserrank, machinePara_.remoteWorldRank));
1856 : }
1857 : } else {
1858 0 : CHK_RET(LocalIpcNotify::Wait(
1859 : stream, dispatcher_, dataNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
1860 : machinePara_.remoteWorldRank));
1861 : }
1862 0 : return HCCL_SUCCESS;
1863 : }
1864 :
1865 0 : HcclResult TransportIbverbs::RxAsync(std::vector<RxMemoryInfo>& rxMems, Stream& stream)
1866 : {
1867 0 : CHK_PRT_RET(rxMems.size() == 0, HCCL_ERROR("Invalid rxMem size[%u]", rxMems.size()), HCCL_E_PARA);
1868 0 : for (auto& mem : rxMems) {
1869 0 : HCCL_DEBUG("RX dst[%p] len[%llu] dstOffset[%llu]", mem.dst, mem.len, mem.srcOffset);
1870 : }
1871 0 : u32 maxLength = 0;
1872 0 : for (u32 i = 0; i < rxMems.size(); i++) {
1873 0 : if (rxMems[i].len > maxLength) {
1874 0 : maxLength = rxMems[i].len;
1875 : }
1876 : }
1877 :
1878 0 : CHK_RET(RxAsync(rxMems[0].srcMemType, rxMems[0].srcOffset, rxMems[0].dst, maxLength, stream));
1879 0 : return HCCL_SUCCESS;
1880 : }
1881 :
1882 0 : HcclResult TransportIbverbs::DataReceivedAck(Stream& stream)
1883 : {
1884 0 : CHK_RET(PostFinAck(stream));
1885 0 : CHK_RET(WaitFinAck(stream));
1886 :
1887 0 : return HCCL_SUCCESS;
1888 : }
1889 :
1890 0 : HcclResult TransportIbverbs::TxWaitDone([[maybe_unused]] Stream& stream) { return HCCL_SUCCESS; }
1891 :
1892 : /* 发送ack消息(同步模式) */
1893 0 : HcclResult TransportIbverbs::TxAck(Stream& stream)
1894 : {
1895 0 : CHK_RET(TxSendWqe(
1896 : remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].addr,
1897 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream, WqeType::WQE_TYPE_ACK_NOTIFY));
1898 0 : return HCCL_SUCCESS;
1899 : }
1900 :
1901 : /* 接收ack消息(同步模式) */
1902 0 : HcclResult TransportIbverbs::RxAck(Stream& stream)
1903 : {
1904 0 : HcclResult ret = LocalIpcNotify::Wait(
1905 0 : stream, dispatcher_, ackNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
1906 : machinePara_.remoteWorldRank);
1907 0 : CHK_PRT_RET(
1908 : ret != HCCL_SUCCESS,
1909 : HCCL_ERROR(
1910 : "[TransportIbverbs][RxAck]errNo[0x%016llx] In lbv exp rx ack, signal wait failed. ", HCCL_ERROR_CODE(ret)),
1911 : ret);
1912 :
1913 0 : return HCCL_SUCCESS;
1914 : }
1915 :
1916 0 : HcclResult TransportIbverbs::TxDataSignal(Stream& stream)
1917 : {
1918 : // 发送data notify同步信息
1919 0 : void* remoteNotifyaddr = remoteDataNotifyMsg_.addr;
1920 0 : HcclResult ret = TxSendWqe(
1921 0 : remoteNotifyaddr, notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream,
1922 : WqeType::WQE_TYPE_DATA_NOTIFY);
1923 0 : CHK_PRT_RET(
1924 : ret != HCCL_SUCCESS,
1925 : HCCL_ERROR(
1926 : "[TransportIbverbs][TxDataSignal]errNo[0x%016llx] In ibv tx data signal, send notify "
1927 : "wqe failed. dstMemPtr[%p], srcMemPtr[%p], srcMemSize[%llu Byte]",
1928 : HCCL_ERROR_CODE(ret), remoteNotifyaddr, notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_),
1929 : ret);
1930 : // 每发送一个data notify wqe, count 自增
1931 0 : return HCCL_SUCCESS;
1932 : }
1933 :
1934 0 : HcclResult TransportIbverbs::RxDataSignal(Stream& stream)
1935 : {
1936 : /* 等待send_ready_event事件 */
1937 0 : CHK_RET(LocalIpcNotify::Wait(
1938 : stream, dispatcher_, dataNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
1939 : machinePara_.remoteWorldRank));
1940 0 : return HCCL_SUCCESS;
1941 : }
1942 :
1943 0 : HcclResult TransportIbverbs::CreateNotifyVectorBuffer(
1944 : std::vector<std::shared_ptr<LocalIpcNotify>>& notifyVector, u8*& exchangeDataPtr, u64& exchangeDataBlankSize)
1945 : {
1946 0 : NotifyLoadType notifyLoadType
1947 0 : = machinePara_.isAicpuModeEn ? NotifyLoadType::DEVICE_NOTIFY : NotifyLoadType::HOST_NOTIFY;
1948 0 : for (u32 i = 0; i < notifyNum_; i++) {
1949 0 : std::shared_ptr<LocalIpcNotify> oneNotify;
1950 0 : CHK_RET(CreateNotifyBuffer(
1951 : oneNotify, MemType::MUILT_NOTIFY_MEM, exchangeDataPtr, exchangeDataBlankSize, notifyLoadType));
1952 0 : notifyVector.push_back(std::move(oneNotify));
1953 0 : }
1954 0 : return HCCL_SUCCESS;
1955 : }
1956 :
1957 0 : HcclResult TransportIbverbs::CreateNotifyBuffer(
1958 : std::shared_ptr<LocalIpcNotify>& localNotify, MemType notifyType, u8*& exchangeDataPtr, u64& exchangeDataBlankSize,
1959 : NotifyLoadType notifyLoadType)
1960 : {
1961 0 : u64 offset = 0;
1962 0 : u64 notifyBaseVa = 0; // notify寄存器虚拟地址
1963 0 : u64 notifyTotalSize = 0;
1964 0 : u32 notifyKey = 0;
1965 :
1966 0 : HcclRtNotify notify = nullptr;
1967 :
1968 : /* 获取notify寄存器虚拟基地址、大小, 物理地址回传值为空 */
1969 0 : struct MrInfoT mrInfo = {};
1970 0 : if (machinePara_.isAicpuModeEn
1971 0 : || (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE
1972 0 : && machinePara_.deviceType != localDeviceType)
1973 0 : || isHybridMode_) {
1974 0 : CHK_RET(HrtRaGetNotifyMrInfo(machinePara_.localDeviceId, nicRdmaHandle_, &mrInfo));
1975 0 : notifyBaseVa = reinterpret_cast<u64>(mrInfo.addr);
1976 0 : notifyTotalSize = mrInfo.size;
1977 0 : notifyKey = mrInfo.lkey;
1978 0 : } else {
1979 0 : u64 notifyBaseVaTmp = 0;
1980 0 : notifyBaseVaTmp = notifyBaseVa;
1981 0 : CHK_RET(HrtRaGetNotifyBaseAddr(nicRdmaHandle_, ¬ifyBaseVa, ¬ifyTotalSize, [this]() -> bool {
1982 : return this->GetStopFlag();
1983 : }));
1984 0 : CHK_PRT_RET(
1985 : ((notifyBaseVaTmp != 0) && (notifyBaseVaTmp != notifyBaseVa)),
1986 : HCCL_ERROR("[Create][NotifyBuffer]In lbv exp init, get base addr failed. notify base va has changed."),
1987 : HCCL_E_INTERNAL);
1988 : }
1989 :
1990 : /* 申请Notify Group ID */
1991 0 : RemoteRankInfo info(machinePara_.localDeviceId, machinePara_.remoteUserrank);
1992 0 : CHK_RET(SalGetBareTgid(&info.remotePid)); // 当前进程id
1993 :
1994 : // atomic write使能场景下,要求写入wr的notify地址是8byte对齐的
1995 0 : u32 offsetAlignSize = INVALID_UINT;
1996 0 : if (machinePara_.enableAtomicWrite) {
1997 : // 映射的MR基地址必定是8字节对齐的
1998 0 : CHK_PRT_RET(
1999 : notifyBaseVa % NOTIFY_VA_ALIGN_EIGHT != 0,
2000 : HCCL_ERROR("%s notifyBaseVa[0x%llx] not %u aligned", __func__, notifyBaseVa, NOTIFY_VA_ALIGN_EIGHT),
2001 : HCCL_E_INTERNAL);
2002 0 : offsetAlignSize = NOTIFY_VA_ALIGN_EIGHT;
2003 : }
2004 0 : CHK_RET(notifyPool_->Alloc(machinePara_.tag, info, localNotify, notifyLoadType, offsetAlignSize));
2005 : // 设置remote id
2006 0 : s64 recvId = 0xFFFFFFFF00000000 | (static_cast<s64>(info.remotePid) & 0xFFFFFFFF);
2007 0 : CHK_RET(localNotify->Grant(recvId));
2008 :
2009 : /* 获取notify虚拟地址 */
2010 0 : CHK_RET(localNotify->GetNotifyOffset(offset));
2011 :
2012 : // notify寄存器的虚拟地址与物理地址偏移相同,所以虚拟地址为虚拟基地址加偏移
2013 0 : u64 notifyVa = notifyBaseVa + offset;
2014 0 : CHK_PRT_RET(
2015 : machinePara_.enableAtomicWrite && (notifyVa % NOTIFY_VA_ALIGN_EIGHT != 0),
2016 : HCCL_ERROR(
2017 : "%s notifyVa[0x%llx] not %u aligned, notifyBaseVa[0x%llx], offset[0x%llx], enableAtomicWrite[%d]", __func__,
2018 : notifyVa, NOTIFY_VA_ALIGN_EIGHT, notifyBaseVa, offset, machinePara_.enableAtomicWrite),
2019 : HCCL_E_INTERNAL);
2020 :
2021 0 : HCCL_INFO(
2022 : "%s notifyBaseVa=0x%llx, notifyTotalSize=0x%x, offset=0x%llx, notifyVa=0x%llx machineType=%d, "
2023 : "notify=%p, notifyType=%d, notifyId=%u, offsetAlignSize[%u]",
2024 : __func__, notifyBaseVa, notifyTotalSize, offset, notifyVa, machinePara_.machineType, notify, notifyType,
2025 : localNotify->notifyId_, offsetAlignSize);
2026 :
2027 0 : if (notifyType != MULTI_QP_DATA_NOTIFY_MEM) {
2028 : /* notify地址注册为mr, 在roce驱动中注册 */
2029 0 : memMsg_[static_cast<u32>(notifyType)].mrRegFlag = 0; // mem注册给网卡标志位
2030 : // 本端notify地址交换给对端
2031 0 : memMsg_[static_cast<u32>(notifyType)].addr = reinterpret_cast<void*>(static_cast<uintptr_t>(notifyVa));
2032 0 : memMsg_[static_cast<u32>(notifyType)].len = notifySize_;
2033 0 : memMsg_[static_cast<u32>(notifyType)].memType = notifyType;
2034 0 : memMsg_[static_cast<u32>(notifyType)].offset = offset;
2035 0 : memMsg_[static_cast<u32>(notifyType)].lkey = mrInfo.lkey;
2036 0 : memMsg_[static_cast<u32>(notifyType)].lkey = notifyKey;
2037 0 : memMsg_[static_cast<u32>(notifyType)].notifyId = localNotify->notifyId_;
2038 :
2039 : /* 拼接要发送的数据 */
2040 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
2041 : exchangeDataPtr, exchangeDataBlankSize, reinterpret_cast<void*>(&memMsg_[static_cast<u32>(notifyType)]),
2042 : sizeof(MemMsg)));
2043 : } else {
2044 0 : MemMsg memMsg;
2045 0 : memMsg.mrRegFlag = 0;
2046 0 : memMsg.addr = reinterpret_cast<void*>(static_cast<uintptr_t>(notifyVa));
2047 0 : memMsg.len = notifySize_;
2048 0 : memMsg.memType = notifyType;
2049 0 : memMsg.offset = offset;
2050 0 : memMsg.notifyId = localNotify->notifyId_;
2051 0 : multiQpDataNotifyMemMsg_.push_back(std::move(memMsg));
2052 0 : CHK_SAFETY_FUNC_RET(
2053 : memcpy_s(exchangeDataPtr, exchangeDataBlankSize, reinterpret_cast<void*>(&memMsg), sizeof(MemMsg)));
2054 : }
2055 :
2056 0 : exchangeDataPtr += sizeof(MemMsg);
2057 0 : exchangeDataBlankSize -= sizeof(MemMsg);
2058 :
2059 0 : return HCCL_SUCCESS;
2060 : }
2061 :
2062 1 : HcclResult TransportIbverbs::RegUserMem(MemType memType, u8*& exchangeDataPtr, u64& exchangeDataBlankSize)
2063 : {
2064 1 : void* memPtr = nullptr;
2065 : u64 memSize;
2066 1 : switch (memType) {
2067 1 : case MemType::USER_INPUT_MEM: {
2068 1 : memPtr = machinePara_.inputMem.ptr();
2069 1 : memSize = machinePara_.inputMem.size();
2070 1 : break;
2071 : }
2072 :
2073 0 : case MemType::USER_OUTPUT_MEM: {
2074 0 : memPtr = machinePara_.outputMem.ptr();
2075 0 : memSize = machinePara_.outputMem.size();
2076 0 : break;
2077 : }
2078 :
2079 0 : default: {
2080 0 : HCCL_ERROR("[Reg][UserMem]not support dst_mem_type=%d", memType);
2081 0 : return HCCL_E_NOT_SUPPORT;
2082 : }
2083 : }
2084 1 : struct MrInfoT mrInfo = {};
2085 1 : mrInfo.addr = memPtr;
2086 1 : mrInfo.size = memSize;
2087 1 : mrInfo.access = access_;
2088 1 : if (mrInfo.size != 0) {
2089 1 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
2090 0 : CHK_RET(HrtRaMrReg(combineQpHandles_[i].qpHandle, &mrInfo));
2091 : }
2092 :
2093 1 : if (UseMultiQp()) {
2094 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2095 0 : CHK_RET(HrtRaMrReg(multiCombineQpHandles_[i].qpHandle, &mrInfo));
2096 : }
2097 : }
2098 1 : memMsg_[static_cast<u32>(memType)].mrRegFlag = REG_VALID;
2099 : }
2100 :
2101 1 : memMsg_[static_cast<u32>(memType)].addr = memPtr;
2102 1 : memMsg_[static_cast<u32>(memType)].len = memSize;
2103 1 : memMsg_[static_cast<u32>(memType)].memType = memType;
2104 1 : memMsg_[static_cast<u32>(memType)].lkey = mrInfo.lkey;
2105 :
2106 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
2107 : exchangeDataPtr, exchangeDataBlankSize, reinterpret_cast<void*>(&memMsg_[static_cast<u32>(memType)]),
2108 : sizeof(MemMsg)));
2109 :
2110 1 : exchangeDataPtr += sizeof(MemMsg);
2111 1 : exchangeDataBlankSize -= sizeof(MemMsg);
2112 :
2113 1 : HCCL_DEBUG("memType=%d mem_ptr=%p mem_size=%llu Byte, key = %u", memType, memPtr, memSize, mrInfo.lkey);
2114 :
2115 1 : return HCCL_SUCCESS;
2116 : }
2117 :
2118 0 : HcclResult TransportIbverbs::RegCustomUserMemWithMsg(
2119 : void* addr, u64 size, MemMsg& memMsg, u8*& exchangeDataPtr, u64& exchangeDataBlankSize)
2120 : {
2121 0 : struct MrInfoT mrInfo = {};
2122 0 : mrInfo.addr = addr;
2123 0 : mrInfo.size = size;
2124 0 : mrInfo.access = access_;
2125 0 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
2126 0 : CHK_RET(HrtRaMrReg(combineQpHandles_[i].qpHandle, &mrInfo));
2127 : }
2128 :
2129 0 : if (UseMultiQp()) {
2130 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2131 0 : CHK_RET(HrtRaMrReg(multiCombineQpHandles_[i].qpHandle, &mrInfo));
2132 : }
2133 : }
2134 :
2135 0 : memMsg.mrRegFlag = REG_VALID;
2136 0 : memMsg.addr = addr;
2137 0 : memMsg.len = size;
2138 0 : memMsg.lkey = mrInfo.lkey;
2139 :
2140 0 : CHK_SAFETY_FUNC_RET(
2141 : memcpy_s(exchangeDataPtr, exchangeDataBlankSize, reinterpret_cast<void*>(&memMsg), sizeof(MemMsg)));
2142 :
2143 0 : exchangeDataPtr += sizeof(MemMsg);
2144 0 : exchangeDataBlankSize -= sizeof(MemMsg);
2145 :
2146 0 : HCCL_DEBUG("mem_ptr=%p mem_size=%llu Byte, key = %u", addr, size, mrInfo.lkey);
2147 :
2148 0 : return HCCL_SUCCESS;
2149 : }
2150 :
2151 0 : HcclResult TransportIbverbs::RegCustomUserMem(u8*& exchangeDataPtr, u64& exchangeDataBlankSize)
2152 : {
2153 0 : u32 deviceMemNum = machinePara_.userDeviceMem.size();
2154 0 : s32 sRet = memcpy_s(exchangeDataPtr, sizeof(u32), reinterpret_cast<void*>(&deviceMemNum), sizeof(u32));
2155 0 : CHK_PRT_RET(
2156 : sRet != EOK,
2157 : HCCL_ERROR(
2158 : "[Set][LocalMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
2159 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
2160 : HCCL_E_MEMORY);
2161 0 : exchangeDataPtr += sizeof(u32);
2162 0 : exchangeDataBlankSize -= sizeof(u32);
2163 :
2164 0 : userDeviceMemMsg_.resize(deviceMemNum);
2165 0 : for (u32 i = 0; i < deviceMemNum; i++) {
2166 0 : RegCustomUserMemWithMsg(
2167 0 : machinePara_.userDeviceMem[i].ptr(), machinePara_.userDeviceMem[i].size(), userDeviceMemMsg_[i],
2168 : exchangeDataPtr, exchangeDataBlankSize);
2169 : }
2170 :
2171 0 : u32 hostMemNum = machinePara_.userHostMem.size();
2172 0 : sRet = memcpy_s(exchangeDataPtr, sizeof(u32), reinterpret_cast<void*>(&hostMemNum), sizeof(u32));
2173 0 : CHK_PRT_RET(
2174 : sRet != EOK,
2175 : HCCL_ERROR(
2176 : "[Set][LocalMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
2177 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
2178 : HCCL_E_MEMORY);
2179 0 : exchangeDataPtr += sizeof(u32);
2180 0 : exchangeDataBlankSize -= sizeof(u32);
2181 :
2182 0 : userHostMemMsg_.resize(hostMemNum);
2183 0 : for (u32 i = 0; i < hostMemNum; i++) {
2184 0 : RegCustomUserMemWithMsg(
2185 0 : machinePara_.userHostMem[i].ptr(), machinePara_.userHostMem[i].size(), userHostMemMsg_[i], exchangeDataPtr,
2186 : exchangeDataBlankSize);
2187 : }
2188 :
2189 0 : return HCCL_SUCCESS;
2190 : }
2191 :
2192 0 : HcclResult TransportIbverbs::GetMemInfo(UserMemType memType, void** dstMemPtr, u64* dstMemSize)
2193 : {
2194 0 : switch (memType) {
2195 0 : case UserMemType::INPUT_MEM: {
2196 0 : *dstMemPtr = remoteMemMsg_[static_cast<u32>(MemType::USER_INPUT_MEM)].addr;
2197 0 : *dstMemSize = remoteMemMsg_[static_cast<u32>(MemType::USER_INPUT_MEM)].len;
2198 0 : break;
2199 : }
2200 :
2201 0 : case UserMemType::OUTPUT_MEM: {
2202 0 : *dstMemPtr = remoteMemMsg_[static_cast<u32>(MemType::USER_OUTPUT_MEM)].addr;
2203 0 : *dstMemSize = remoteMemMsg_[static_cast<u32>(MemType::USER_OUTPUT_MEM)].len;
2204 0 : break;
2205 : }
2206 :
2207 0 : default: {
2208 0 : HCCL_ERROR("[Get][MemInfo]not support dst_mem_type=%d", memType);
2209 0 : return HCCL_E_NOT_SUPPORT;
2210 : }
2211 : }
2212 0 : return HCCL_SUCCESS;
2213 : }
2214 :
2215 0 : HcclResult TransportIbverbs::GetRemoteAddr(MemType memType, u8*& exchangeDataPtr, u64& exchangeDataBlankSize)
2216 : {
2217 0 : if (memType != MULTI_QP_DATA_NOTIFY_MEM) {
2218 0 : s32 sRet = memcpy_s(&remoteMemMsg_[static_cast<u32>(memType)], sizeof(MemMsg), exchangeDataPtr, sizeof(MemMsg));
2219 0 : CHK_PRT_RET(
2220 : sRet != EOK,
2221 : HCCL_ERROR(
2222 : "[Get][RemoteAddr]errNo[0x%016llx] In lbv exp get remote addr, "
2223 : "memcpy failed. errorno[%d], params:destMaxSize[%zu],count[%zu]",
2224 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(MemMsg), sizeof(MemMsg)),
2225 : HCCL_E_MEMORY);
2226 0 : CHK_PTR_NULL(remoteMemMsg_[static_cast<u32>(memType)].addr);
2227 : } else {
2228 0 : MemMsg memMsg;
2229 0 : s32 sRet = memcpy_s(&memMsg, sizeof(MemMsg), exchangeDataPtr, sizeof(MemMsg));
2230 0 : CHK_PRT_RET(
2231 : sRet != EOK,
2232 : HCCL_ERROR(
2233 : "[Get][RemoteAddr]errNo[0x%016llx] In lbv exp get remote addr, "
2234 : "memcpy failed. errorno[%d], params:destMaxSize[%zu],count[%zu]",
2235 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(MemMsg), sizeof(MemMsg)),
2236 : HCCL_E_MEMORY);
2237 0 : CHK_PTR_NULL(memMsg.addr);
2238 0 : multiQpDataNotifyRemoteMemMsg_.push_back(std::move(memMsg));
2239 : }
2240 :
2241 0 : exchangeDataPtr += sizeof(MemMsg);
2242 0 : exchangeDataBlankSize -= sizeof(MemMsg);
2243 0 : HCCL_INFO(
2244 : "GetRemoteAddr success: memType=%d, addr=%p len=%llu, notifyId=%u", static_cast<int32_t>(memType),
2245 : remoteMemMsg_[static_cast<u32>(memType)].addr, remoteMemMsg_[static_cast<u32>(memType)].len,
2246 : remoteMemMsg_[static_cast<u32>(memType)].notifyId);
2247 0 : return HCCL_SUCCESS;
2248 : }
2249 :
2250 0 : HcclResult TransportIbverbs::GetIndOpRemoteAddr(u8*& exchangeDataPtr, u64& exchangeDataBlankSize)
2251 : {
2252 0 : u32 remoteDmemNum = 0;
2253 0 : s32 sRet = memcpy_s(reinterpret_cast<void*>(&remoteDmemNum), sizeof(u32), exchangeDataPtr, sizeof(u32));
2254 0 : CHK_PRT_RET(
2255 : sRet != EOK,
2256 : HCCL_ERROR(
2257 : "[Get][RemoteMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
2258 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
2259 : HCCL_E_MEMORY);
2260 0 : exchangeDataPtr += sizeof(u32);
2261 0 : exchangeDataBlankSize -= sizeof(u32);
2262 :
2263 0 : remoteUserDeviceMemMsg_.resize(remoteDmemNum);
2264 0 : for (u32 i = 0; i < remoteDmemNum; i++) {
2265 0 : sRet = memcpy_s(&remoteUserDeviceMemMsg_[i], sizeof(MemMsg), exchangeDataPtr, sizeof(MemMsg));
2266 0 : CHK_PRT_RET(
2267 : sRet != EOK,
2268 : HCCL_ERROR(
2269 : "[Get][GetCustomRemoteAddr]errNo[0x%016llx] In lbv exp get remote addr, "
2270 : "memcpy failed. errorno[%d], params:destMaxSize[%zu],count[%zu]",
2271 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(MemMsg), sizeof(MemMsg)),
2272 : HCCL_E_MEMORY);
2273 0 : exchangeDataPtr += sizeof(MemMsg);
2274 0 : exchangeDataBlankSize -= sizeof(MemMsg);
2275 0 : CHK_PTR_NULL(remoteUserDeviceMemMsg_[i].addr);
2276 : }
2277 :
2278 0 : u32 remoteHmemNum = 0;
2279 0 : sRet = memcpy_s(reinterpret_cast<void*>(&remoteHmemNum), sizeof(u32), exchangeDataPtr, sizeof(u32));
2280 0 : CHK_PRT_RET(
2281 : sRet != EOK,
2282 : HCCL_ERROR(
2283 : "[Get][RemoteMem]errNo[0x%016llx] memory copy failed. errorno[%d], params:dstMaxSize[%zu],cnt[%zu]",
2284 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(u32), sizeof(u32)),
2285 : HCCL_E_MEMORY);
2286 0 : exchangeDataPtr += sizeof(u32);
2287 0 : exchangeDataBlankSize -= sizeof(u32);
2288 :
2289 0 : remoteUserHostMemMsg_.resize(remoteHmemNum);
2290 0 : for (u32 i = 0; i < remoteHmemNum; i++) {
2291 0 : sRet = memcpy_s(&remoteUserHostMemMsg_[i], sizeof(MemMsg), exchangeDataPtr, sizeof(MemMsg));
2292 0 : CHK_PRT_RET(
2293 : sRet != EOK,
2294 : HCCL_ERROR(
2295 : "[Get][GetCustomRemoteAddr]errNo[0x%016llx] In lbv exp get remote addr, "
2296 : "memcpy failed. errorno[%d], params:destMaxSize[%zu],count[%zu]",
2297 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(MemMsg), sizeof(MemMsg)),
2298 : HCCL_E_MEMORY);
2299 0 : exchangeDataPtr += sizeof(MemMsg);
2300 0 : exchangeDataBlankSize -= sizeof(MemMsg);
2301 0 : CHK_PTR_NULL(remoteUserHostMemMsg_[i].addr);
2302 : }
2303 :
2304 0 : return HCCL_SUCCESS;
2305 : }
2306 :
2307 0 : HcclResult TransportIbverbs::GetRemoteNotifyAddr(u8*& exchangeDataPtr, u64& exchangeDataBlankSize, MemMsg& memMsg)
2308 : {
2309 0 : s32 sRet = memcpy_s(&memMsg, sizeof(MemMsg), exchangeDataPtr, sizeof(MemMsg));
2310 0 : CHK_PRT_RET(
2311 : sRet != EOK,
2312 : HCCL_ERROR(
2313 : "[Get][GetRemoteNotifyAddr]errNo[0x%016llx] In lbv exp get remote addr, "
2314 : "memcpy failed. errorno[%d], params:destMaxSize[%zu],count[%zu]",
2315 : HCCL_ERROR_CODE(HCCL_E_MEMORY), sRet, sizeof(MemMsg), sizeof(MemMsg)),
2316 : HCCL_E_MEMORY);
2317 :
2318 0 : exchangeDataPtr += sizeof(MemMsg);
2319 0 : exchangeDataBlankSize -= sizeof(MemMsg);
2320 0 : CHK_PTR_NULL(memMsg.addr);
2321 0 : HCCL_INFO("GetRemoteNotifyAddr success: addr=%p len=%llu", memMsg.addr, memMsg.len);
2322 0 : return HCCL_SUCCESS;
2323 : }
2324 :
2325 0 : HcclResult TransportIbverbs::CreateNotifyValueBuffer()
2326 : {
2327 0 : if (!machinePara_.userMemEnable && !machinePara_.drainEnable) {
2328 0 : HCCL_INFO("userMemEnable is false, no need to create notify value buffer");
2329 0 : return HCCL_SUCCESS;
2330 : }
2331 0 : std::unique_lock<std::mutex> lock(notifyValueMutex_[machinePara_.deviceLogicId]);
2332 0 : if (notifyValueMem_[machinePara_.deviceLogicId].ptr() == nullptr) {
2333 0 : u64 notifyVaule = 1; // notify值写1表示record
2334 0 : CHK_RET(DeviceMem::alloc(notifyValueMem_[machinePara_.deviceLogicId], notifyValueSize_));
2335 0 : HCCL_DEBUG(
2336 : "create notify value buffer[%p], size[%u]", notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_);
2337 :
2338 0 : CHK_RET(hrtMemSyncCopy(
2339 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifyValueMem_[machinePara_.deviceLogicId].size(),
2340 : ¬ifyVaule, notifySize_, HcclRtMemcpyKind::HCCL_RT_MEMCPY_KIND_HOST_TO_DEVICE));
2341 : }
2342 0 : lock.unlock();
2343 :
2344 0 : struct MrInfoT mrInfo = {};
2345 0 : mrInfo.addr = notifyValueMem_[machinePara_.deviceLogicId].ptr();
2346 0 : mrInfo.size = notifySize_;
2347 0 : mrInfo.access = access_;
2348 :
2349 0 : for (u32 i = 0; i < combineQpHandles_.size(); i++) {
2350 0 : CHK_RET(HrtRaMrReg(combineQpHandles_[i].qpHandle, &mrInfo));
2351 : }
2352 :
2353 0 : if (UseMultiQp()) {
2354 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2355 0 : CHK_RET(HrtRaMrReg(multiCombineQpHandles_[i].qpHandle, &mrInfo));
2356 : }
2357 : }
2358 0 : memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].mrRegFlag = REG_VALID;
2359 0 : memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].addr = notifyValueMem_[machinePara_.deviceLogicId].ptr();
2360 0 : memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].len = notifySize_;
2361 0 : memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].memType = MemType::NOTIFY_SRC_MEM;
2362 0 : memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].lkey = mrInfo.lkey;
2363 :
2364 0 : HCCL_DEBUG("notifyValueMem_=%p", notifyValueMem_[machinePara_.deviceLogicId].ptr());
2365 :
2366 0 : return HCCL_SUCCESS;
2367 0 : }
2368 34 : void TransportIbverbs::DestroySignal()
2369 : {
2370 34 : dataNotify_ = nullptr;
2371 :
2372 34 : ackNotify_ = nullptr;
2373 :
2374 34 : dataAckNotify_ = nullptr;
2375 :
2376 34 : multiQpDataNotify_.clear();
2377 34 : }
2378 :
2379 : /* 发送ack消息(同步模式) */
2380 0 : HcclResult TransportIbverbs::TxPrepare(Stream& stream)
2381 : {
2382 0 : HcclResult ret = LocalIpcNotify::Wait(
2383 0 : stream, dispatcher_, ackNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
2384 : machinePara_.remoteWorldRank);
2385 0 : CHK_PRT_RET(
2386 : ret != HCCL_SUCCESS,
2387 : HCCL_ERROR(
2388 : "[TransportIbverbs][TxPrepare]errNo[0x%016llx] In lbv exp rx ack, signal wait failed. ",
2389 : HCCL_ERROR_CODE(ret)),
2390 : ret);
2391 :
2392 0 : return HCCL_SUCCESS;
2393 : }
2394 :
2395 : /* 接收ack消息(同步模式) */
2396 0 : HcclResult TransportIbverbs::RxPrepare(Stream& stream)
2397 : {
2398 0 : CHK_RET(TxSendWqe(
2399 : remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].addr,
2400 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream, WqeType::WQE_TYPE_ACK_NOTIFY));
2401 0 : return HCCL_SUCCESS;
2402 : }
2403 :
2404 0 : HcclResult TransportIbverbs::TxData(UserMemType dstMemType, u64 dstOffset, const void* src, u64 len, Stream& stream)
2405 : {
2406 0 : std::vector<WqeInfo> wqeInfoVec;
2407 0 : struct WrAuxInfo aux = {};
2408 0 : HCCL_DEBUG("TX src[%p] len[%llu] dstOffset[%llu]", src, len, dstOffset);
2409 :
2410 0 : if (src != nullptr) {
2411 0 : CHK_RET(TxPayLoad(dstMemType, dstOffset, src, len, WqeType::WQE_TYPE_DATA, aux, wqeInfoVec));
2412 : }
2413 :
2414 0 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE) {
2415 0 : CHK_RET(RdmaSendAsync(wqeInfoVec, stream, false));
2416 : } else {
2417 0 : CHK_RET(RdmaSendAsyncHostNIC(wqeInfoVec, stream));
2418 : }
2419 0 : return HCCL_SUCCESS;
2420 0 : }
2421 :
2422 0 : HcclResult TransportIbverbs::RxData(
2423 : [[maybe_unused]] UserMemType srcMemType, [[maybe_unused]] u64 srcOffset, [[maybe_unused]] void* dst,
2424 : [[maybe_unused]] u64 len, [[maybe_unused]] Stream& stream)
2425 : {
2426 0 : return HCCL_SUCCESS;
2427 : }
2428 :
2429 0 : HcclResult TransportIbverbs::TxDone(Stream& stream)
2430 : {
2431 : // 发送数据接收确认notify
2432 0 : CHK_RET(TxSendWqe(
2433 : remoteMemMsg_[static_cast<u32>(MemType::DATA_NOTIFY_MEM)].addr,
2434 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream, WqeType::WQE_TYPE_DATA_NOTIFY));
2435 : // 接收数据接收确认notify
2436 0 : CHK_RET(LocalIpcNotify::Wait(
2437 : stream, dispatcher_, dataAckNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
2438 : machinePara_.remoteWorldRank));
2439 0 : return HCCL_SUCCESS;
2440 : }
2441 :
2442 0 : HcclResult TransportIbverbs::RxDone(Stream& stream)
2443 : {
2444 : // 接收数据接收确认notify
2445 0 : CHK_RET(LocalIpcNotify::Wait(
2446 : stream, dispatcher_, dataNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
2447 : machinePara_.remoteWorldRank));
2448 :
2449 : // 发送数据接收确认notify
2450 0 : CHK_RET(TxSendWqe(
2451 : remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].addr,
2452 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream, WqeType::WQE_TYPE_DATA_ACK_NOTIFY));
2453 0 : return HCCL_SUCCESS;
2454 : }
2455 :
2456 0 : HcclResult TransportIbverbs::PostReady(Stream& stream)
2457 : {
2458 0 : CHK_RET(TxSendWqe(
2459 : remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].addr,
2460 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream, WqeType::WQE_TYPE_ACK_NOTIFY));
2461 0 : return HCCL_SUCCESS;
2462 : }
2463 :
2464 0 : HcclResult TransportIbverbs::WaitReady(Stream& stream)
2465 : {
2466 0 : CHK_RET(LocalIpcNotify::Wait(
2467 : stream, dispatcher_, ackNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
2468 : machinePara_.remoteWorldRank));
2469 0 : return HCCL_SUCCESS;
2470 : }
2471 :
2472 0 : HcclResult TransportIbverbs::PostFin(Stream& stream)
2473 : {
2474 : // 发送data notify同步信息
2475 0 : void* remoteNotifyaddr = remoteDataNotifyMsg_.addr;
2476 0 : HcclResult ret = TxSendWqe(
2477 0 : remoteNotifyaddr, notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream,
2478 : WqeType::WQE_TYPE_DATA_NOTIFY);
2479 0 : CHK_PRT_RET(
2480 : ret != HCCL_SUCCESS,
2481 : HCCL_ERROR(
2482 : "[TransportIbverbs][PostFin]errNo[0x%016llx] In ibv tx data signal, send notify "
2483 : "wqe failed. dstMemPtr[%p], srcMemPtr[%p], srcMemSize[%llu]",
2484 : HCCL_ERROR_CODE(ret), remoteNotifyaddr, notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_),
2485 : ret);
2486 : // 每发送一个data notify wqe, count 自增
2487 0 : return HCCL_SUCCESS;
2488 : }
2489 :
2490 0 : HcclResult TransportIbverbs::WaitFin(Stream& stream)
2491 : {
2492 0 : CHK_RET(LocalIpcNotify::Wait(
2493 : stream, dispatcher_, dataNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
2494 : machinePara_.remoteWorldRank));
2495 0 : return HCCL_SUCCESS;
2496 : }
2497 :
2498 0 : HcclResult TransportIbverbs::PostFinAck(Stream& stream)
2499 : {
2500 0 : CHK_RET(TxSendWqe(
2501 : remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].addr,
2502 : notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_, stream, WqeType::WQE_TYPE_DATA_ACK_NOTIFY));
2503 0 : return HCCL_SUCCESS;
2504 : }
2505 :
2506 0 : HcclResult TransportIbverbs::WaitFinAck(Stream& stream)
2507 : {
2508 0 : CHK_RET(LocalIpcNotify::Wait(
2509 : stream, dispatcher_, dataAckNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
2510 : machinePara_.remoteWorldRank));
2511 0 : return HCCL_SUCCESS;
2512 : }
2513 :
2514 0 : HcclResult TransportIbverbs::Post(u32 notifyIdx, Stream& stream)
2515 : {
2516 : // 校验notifyIdx有效性
2517 0 : bool bRet = (notifyIdx >= notifyNum_);
2518 0 : CHK_PRT_RET(
2519 : bRet,
2520 : HCCL_ERROR(
2521 : "[TransportIbverbs][Post]notifyNum[%u], notifyIdx[%u] out of range[0, %u]", notifyNum_, notifyIdx,
2522 : notifyNum_ - 1),
2523 : HCCL_E_INTERNAL);
2524 :
2525 : // 每个QP发送一个指定idx的notify
2526 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2527 0 : CHK_RET(TxSendNotifyWqe(
2528 : userMultiQpRemoteNotifyMsg_[i][notifyIdx], notifyValueMem_[machinePara_.deviceLogicId].ptr(), notifySize_,
2529 : stream));
2530 : }
2531 0 : return HCCL_SUCCESS;
2532 : }
2533 :
2534 0 : HcclResult TransportIbverbs::Wait(u32 notifyIdx, Stream& stream, const u32 timeOut)
2535 : {
2536 : // 校验notifyIdx有效性
2537 0 : bool bRet = (notifyIdx >= notifyNum_);
2538 0 : CHK_PRT_RET(
2539 : bRet,
2540 : HCCL_ERROR(
2541 : "[TransportIbverbs][Wait]notifyNum[%u], notifyIdx[%u] out of range[0, %u]", notifyNum_, notifyIdx,
2542 : notifyNum_ - 1),
2543 : HCCL_E_INTERNAL);
2544 :
2545 : // 每个qp接收一个指定idx的notify
2546 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2547 0 : CHK_RET(LocalIpcNotify::Wait(
2548 : stream, dispatcher_, userMultiQpLocalNotify_[i][notifyIdx], INVALID_VALUE_STAGE, timeOut,
2549 : machinePara_.localUserrank, machinePara_.remoteWorldRank));
2550 : }
2551 0 : return HCCL_SUCCESS;
2552 : }
2553 :
2554 0 : HcclResult TransportIbverbs::GetLocalRdmaNotify(std::vector<HcclSignalInfo>& rdmaNotify)
2555 : {
2556 : HcclSignalInfo signalInfo;
2557 0 : CHK_SMART_PTR_NULL(ackNotify_);
2558 0 : CHK_RET(ackNotify_->GetNotifyData(signalInfo));
2559 0 : rdmaNotify.push_back(signalInfo);
2560 0 : CHK_SMART_PTR_NULL(ackNotify_);
2561 0 : CHK_RET(dataNotify_->GetNotifyData(signalInfo));
2562 0 : rdmaNotify.push_back(signalInfo);
2563 0 : CHK_SMART_PTR_NULL(ackNotify_);
2564 0 : CHK_RET(dataAckNotify_->GetNotifyData(signalInfo));
2565 0 : rdmaNotify.push_back(signalInfo);
2566 : // 提取新增的notify资源
2567 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2568 0 : for (u32 j = 0; j < notifyNum_; j++) {
2569 0 : CHK_SMART_PTR_NULL(userMultiQpLocalNotify_[i][j]);
2570 0 : CHK_RET(userMultiQpLocalNotify_[i][j]->GetNotifyData(signalInfo));
2571 0 : rdmaNotify.push_back(signalInfo);
2572 : }
2573 0 : if (qpsPerConnection_ > 1) {
2574 0 : CHK_SMART_PTR_NULL(multiQpDataNotify_[i]);
2575 0 : CHK_RET(multiQpDataNotify_[i]->GetNotifyData(signalInfo));
2576 0 : rdmaNotify.push_back(signalInfo);
2577 : }
2578 0 : HCCL_DEBUG(
2579 : "[TransportIbverbs][GetLocalRdmaNotify] resId[%llu] addr[%llu]", rdmaNotify.back().resId,
2580 : rdmaNotify.back().addr);
2581 : }
2582 0 : return HCCL_SUCCESS;
2583 : }
2584 :
2585 0 : HcclResult TransportIbverbs::GetRemoteRdmaNotifyAddrKey(std::vector<AddrKey>& rdmaNotify)
2586 : {
2587 0 : if (remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].addr == nullptr) {
2588 0 : HCCL_ERROR("[TransportIbverbs][GetRemoteRdmaNotifyAddrKey] ackNotify is null!");
2589 0 : return HCCL_E_PTR;
2590 0 : } else if (remoteMemMsg_[static_cast<u32>(MemType::DATA_NOTIFY_MEM)].addr == nullptr) {
2591 0 : HCCL_ERROR("[TransportIbverbs][GetRemoteRdmaNotifyAddrKey] dataNotify is null!");
2592 0 : return HCCL_E_PTR;
2593 0 : } else if (remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].addr == nullptr) {
2594 0 : HCCL_ERROR("[TransportIbverbs][GetRemoteRdmaNotifyAddrKey] dataAckNotify is null!");
2595 0 : return HCCL_E_PTR;
2596 : }
2597 0 : AddrKey notifyDetails;
2598 0 : notifyDetails.addr = reinterpret_cast<u64>(remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].addr);
2599 0 : notifyDetails.key = reinterpret_cast<u32>(remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].lkey);
2600 0 : notifyDetails.notifyId = remoteMemMsg_[static_cast<u32>(MemType::ACK_NOTIFY_MEM)].notifyId;
2601 0 : rdmaNotify.push_back(notifyDetails);
2602 0 : notifyDetails.addr = reinterpret_cast<u64>(remoteMemMsg_[static_cast<u32>(MemType::DATA_NOTIFY_MEM)].addr);
2603 0 : notifyDetails.key = reinterpret_cast<u32>(remoteMemMsg_[static_cast<u32>(MemType::DATA_NOTIFY_MEM)].lkey);
2604 0 : notifyDetails.notifyId = remoteMemMsg_[static_cast<u32>(MemType::DATA_NOTIFY_MEM)].notifyId;
2605 0 : rdmaNotify.push_back(notifyDetails);
2606 0 : notifyDetails.addr = reinterpret_cast<u64>(remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].addr);
2607 0 : notifyDetails.key = reinterpret_cast<u32>(remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].lkey);
2608 0 : notifyDetails.notifyId = remoteMemMsg_[static_cast<u32>(MemType::DATA_ACK_NOTIFY_MEM)].notifyId;
2609 0 : rdmaNotify.push_back(notifyDetails);
2610 :
2611 : // 获取新增的多notify资源
2612 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2613 0 : for (u32 j = 0; j < notifyNum_; j++) {
2614 0 : notifyDetails.addr = reinterpret_cast<u64>(userMultiQpRemoteNotifyMsg_[i][j].addr);
2615 0 : notifyDetails.key = reinterpret_cast<u32>(userMultiQpRemoteNotifyMsg_[i][j].lkey);
2616 0 : notifyDetails.notifyId = userMultiQpRemoteNotifyMsg_[i][j].notifyId;
2617 0 : rdmaNotify.push_back(notifyDetails);
2618 : }
2619 0 : if (qpsPerConnection_ > 1) {
2620 0 : notifyDetails.addr = reinterpret_cast<u64>(multiQpDataNotifyRemoteMemMsg_[i].addr);
2621 0 : notifyDetails.key = reinterpret_cast<u32>(multiQpDataNotifyRemoteMemMsg_[i].lkey);
2622 0 : notifyDetails.notifyId = multiQpDataNotifyRemoteMemMsg_[i].notifyId;
2623 0 : rdmaNotify.push_back(notifyDetails);
2624 : }
2625 0 : HCCL_DEBUG(
2626 : "[TransportIbverbs][GetRemoteRdmaNotifyAddrKey]remote addr[0x%llx], key[%lu], notifyId[%u]",
2627 : rdmaNotify.back().addr, rdmaNotify.back().key, rdmaNotify.back().notifyId);
2628 : }
2629 0 : return HCCL_SUCCESS;
2630 : }
2631 :
2632 0 : HcclResult TransportIbverbs::GetLocalNotifyValueAddrKey(std::vector<AddrKey>& notifyValue)
2633 : {
2634 0 : if (memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].addr == nullptr) {
2635 0 : HCCL_ERROR("[TransportIbverbs][GetLocalNotifyValueAddrKey] notifyValue is null!");
2636 0 : return HCCL_E_PTR;
2637 : }
2638 :
2639 0 : AddrKey notifyDetails;
2640 0 : notifyDetails.addr = reinterpret_cast<u64>(memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].addr);
2641 0 : notifyDetails.key = reinterpret_cast<u32>(memMsg_[static_cast<u32>(MemType::NOTIFY_SRC_MEM)].lkey);
2642 0 : notifyValue.push_back(notifyDetails);
2643 0 : return HCCL_SUCCESS;
2644 : }
2645 :
2646 0 : HcclResult TransportIbverbs::GetRemoteMemKey(UserMemType memType, uint32_t* remoteMemKey)
2647 : {
2648 0 : switch (memType) {
2649 0 : case UserMemType::INPUT_MEM:
2650 : case UserMemType::OUTPUT_MEM:
2651 0 : *remoteMemKey = remoteMemMsg_[static_cast<u32>(memType)].lkey;
2652 0 : break;
2653 :
2654 0 : default:
2655 0 : HCCL_ERROR("[Get][RemoteMemKey]not support dst_mem_type=%d", memType);
2656 0 : return HCCL_E_NOT_SUPPORT;
2657 : }
2658 0 : return HCCL_SUCCESS;
2659 : }
2660 :
2661 0 : HcclResult TransportIbverbs::GetLocalMemDetails(UserMemType memType, MemDetails& memDetails)
2662 : {
2663 0 : switch (memType) {
2664 0 : case UserMemType::INPUT_MEM:
2665 : case UserMemType::OUTPUT_MEM:
2666 0 : memDetails.addr = reinterpret_cast<u64>(memMsg_[static_cast<u32>(memType)].addr);
2667 0 : memDetails.size = memMsg_[static_cast<u32>(memType)].len;
2668 0 : memDetails.key = memMsg_[static_cast<u32>(memType)].lkey;
2669 0 : break;
2670 :
2671 0 : default:
2672 0 : HCCL_ERROR("[Get][LocalMemDetails]not support dst_mem_type=%d", memType);
2673 0 : return HCCL_E_NOT_SUPPORT;
2674 : }
2675 0 : return HCCL_SUCCESS;
2676 : }
2677 :
2678 0 : HcclResult TransportIbverbs::GetAiQpInfo(std::vector<HcclQpInfoV2>& aiQpInfo)
2679 : {
2680 0 : aiQpInfo.resize(combineAiQpInfos_.size() + 1);
2681 :
2682 0 : aiQpInfo[0].qpPtr = combineAiQpInfo_.aiQpInfo.aiQpAddr;
2683 0 : aiQpInfo[0].sqIndex = combineAiQpInfo_.aiQpInfo.sqIndex;
2684 0 : aiQpInfo[0].dbIndex = combineAiQpInfo_.aiQpInfo.dbIndex;
2685 0 : HCCL_DEBUG(
2686 : "[TransportIbverbs][GetAiQpInfo] i[0] qpPtr[%llu] sqIndex[%u] dbIndex[%u]", aiQpInfo[0].qpPtr,
2687 : aiQpInfo[0].sqIndex, aiQpInfo[0].dbIndex);
2688 0 : for (u32 i = 1, j = 0; i < aiQpInfo.size(); i++, j++) {
2689 0 : aiQpInfo[i].qpPtr = combineAiQpInfos_[j].aiQpInfo.aiQpAddr;
2690 0 : aiQpInfo[i].sqIndex = combineAiQpInfos_[j].aiQpInfo.sqIndex;
2691 0 : aiQpInfo[i].dbIndex = combineAiQpInfos_[j].aiQpInfo.dbIndex;
2692 0 : HCCL_DEBUG(
2693 : "[TransportIbverbs][GetAiQpInfo] i[%u] qpPtr[%llu] sqIndex[%u] dbIndex[%u]", i, aiQpInfo[i].qpPtr,
2694 : aiQpInfo[i].sqIndex, aiQpInfo[i].dbIndex);
2695 : }
2696 0 : return HCCL_SUCCESS;
2697 : }
2698 :
2699 0 : HcclResult TransportIbverbs::GetAiRMAQueueInfo(std::vector<HcclAiRMAQueueInfo>& aiRMAQueueInfo)
2700 : {
2701 0 : bool isSupport = false;
2702 0 : CHK_RET(IsSupportAIVNormalQP(machinePara_.localDeviceId, isSupport));
2703 0 : CHK_PRT_RET(
2704 : isSupport == false,
2705 : HCCL_ERROR(
2706 : "[IsSupportCQCoverNormalQP]"
2707 : "devicePhyId[%u] not support",
2708 : machinePara_.localDeviceId),
2709 : HCCL_E_NOT_SUPPORT);
2710 :
2711 0 : u32 sl = GetExternalInputRdmaServerLevel();
2712 0 : if (machinePara_.sl != HCCL_COMM_SERVICE_LEVEL_CONFIG_NOT_SET) {
2713 0 : sl = machinePara_.sl;
2714 : }
2715 0 : HCCL_INFO(
2716 : "[TransportIbverbs][GetAiRMAQueueInfo] localUserRank[%u], remoteUserrank[%u], sl[%u]",
2717 : machinePara_.localUserrank, machinePara_.remoteUserrank, sl);
2718 0 : aiRMAQueueInfo.resize(combineAiQpInfos_.size() + 1);
2719 0 : CopyAiWQInfo(aiRMAQueueInfo[0].sq, combineAiQpInfo_.aiQpInfo.dataPlaneInfo.sq, DBMode::HW_DB, sl);
2720 0 : CopyAiWQInfo(aiRMAQueueInfo[0].rq, combineAiQpInfo_.aiQpInfo.dataPlaneInfo.rq, DBMode::SW_DB, sl);
2721 0 : CopyAiCQInfo(aiRMAQueueInfo[0].scq, combineAiQpInfo_.aiQpInfo.dataPlaneInfo.scq, DBMode::SW_DB);
2722 0 : CopyAiCQInfo(aiRMAQueueInfo[0].rcq, combineAiQpInfo_.aiQpInfo.dataPlaneInfo.rcq, DBMode::SW_DB);
2723 :
2724 : // 预留多QP的能力; 当前主要是单QP场景
2725 0 : for (u32 i = 1, j = 0; i < aiRMAQueueInfo.size(); i++, j++) {
2726 0 : CopyAiWQInfo(aiRMAQueueInfo[i].sq, combineAiQpInfos_[j].aiQpInfo.dataPlaneInfo.sq, DBMode::HW_DB, sl);
2727 0 : CopyAiWQInfo(aiRMAQueueInfo[i].rq, combineAiQpInfos_[j].aiQpInfo.dataPlaneInfo.rq, DBMode::SW_DB, sl);
2728 0 : CopyAiCQInfo(aiRMAQueueInfo[i].scq, combineAiQpInfos_[j].aiQpInfo.dataPlaneInfo.scq, DBMode::SW_DB);
2729 0 : CopyAiCQInfo(aiRMAQueueInfo[i].rcq, combineAiQpInfos_[j].aiQpInfo.dataPlaneInfo.rcq, DBMode::SW_DB);
2730 : }
2731 0 : return HCCL_SUCCESS;
2732 : }
2733 :
2734 0 : HcclResult TransportIbverbs::WriteCommon(
2735 : const void* remoteAddr, const void* localAddr, u64 length, Stream& stream, WqeType wqeType, struct WrAuxInfo& aux)
2736 : {
2737 : // 单qp & 多qp
2738 0 : std::vector<WqeInfo> wqeInfoVec;
2739 0 : wqeInfoVec.reserve(WQE_RESERVE_LENGTH);
2740 0 : HCCL_DEBUG("write localAddr[%p] remoteAddr[%p] len[%llu] remoteOffset[%llu]", localAddr, remoteAddr, length);
2741 :
2742 0 : if (localAddr != nullptr) {
2743 : // 为保证单算子下不同数据量下子图的结构相同,zero byte message 时也需要下发task
2744 0 : u32 txSendDataTimes = (length == 0) ? 1 : (length + RDMA_SEND_MAX_SIZE - 1) / RDMA_SEND_MAX_SIZE;
2745 0 : CHK_RET(ConstructPayLoadWqe(
2746 : const_cast<void*>(remoteAddr), const_cast<void*>(localAddr), length, wqeType, aux, wqeInfoVec,
2747 : txSendDataTimes));
2748 : }
2749 :
2750 0 : u32 maxLength = 0;
2751 0 : for (u32 i = 0; i < wqeInfoVec.size(); i++) {
2752 0 : if (wqeInfoVec[i].wqeData.memList.len > maxLength) {
2753 0 : maxLength = wqeInfoVec[i].wqeData.memList.len;
2754 : }
2755 : }
2756 :
2757 0 : u32 actualMultiQpNum = GetActualQpNum(maxLength);
2758 :
2759 0 : HCCL_DEBUG(
2760 : "[TransportIbverbs][TxSendDataAndNotify] UseMultiQp[%d] MultiQpNum[%u] actualMultiQpNum[%u] maxLength[%u]",
2761 : UseMultiQp(), qpsPerConnection_, actualMultiQpNum, maxLength);
2762 0 : if (UseMultiQp() && actualMultiQpNum != 1 && actualMultiQpNum <= qpsPerConnection_ && maxLength != 0) {
2763 0 : std::vector<std::vector<WqeInfo>> multiQpWqeInfoVct(actualMultiQpNum, wqeInfoVec);
2764 0 : for (u32 i = 0; i < wqeInfoVec.size(); i++) {
2765 0 : WqeInfo tmpWqeInfo = wqeInfoVec[i];
2766 0 : u32 curLen = tmpWqeInfo.wqeData.memList.len;
2767 0 : std::vector<u32> splittedLen = RdmaLengthSplit(curLen, actualMultiQpNum);
2768 0 : uint64_t curSrcAddr = tmpWqeInfo.wqeData.memList.addr;
2769 0 : uint64_t curDstAddr = tmpWqeInfo.wqeData.dstAddr;
2770 0 : for (u32 qpIndex = 0; qpIndex < actualMultiQpNum; qpIndex++) {
2771 0 : multiQpWqeInfoVct[qpIndex][i].wqeData.memList.len = splittedLen[qpIndex];
2772 0 : multiQpWqeInfoVct[qpIndex][i].wqeData.memList.addr = curSrcAddr;
2773 0 : multiQpWqeInfoVct[qpIndex][i].wqeData.dstAddr = curDstAddr;
2774 0 : curSrcAddr += splittedLen[qpIndex];
2775 0 : curDstAddr += splittedLen[qpIndex];
2776 : }
2777 0 : }
2778 :
2779 : // useOneDoorbell 配置成true。最后一个payload去按doorbell
2780 0 : for (u32 qpIndex = 0; qpIndex < actualMultiQpNum; qpIndex++) {
2781 0 : CHK_RET(RdmaSendAsync(
2782 : multiQpWqeInfoVct[qpIndex], stream, true, qpIndex)); // 多QP使用同一个stream异步doorbell触发
2783 : }
2784 0 : } else {
2785 0 : if (machinePara_.nicDeploy == NICDeployment::NIC_DEPLOYMENT_DEVICE) {
2786 0 : CHK_RET(RdmaSendAsync(wqeInfoVec, stream, GetUseOneDoorbellValue()));
2787 : } else {
2788 0 : CHK_RET(RdmaSendAsyncHostNIC(wqeInfoVec, stream));
2789 : }
2790 : }
2791 0 : return HCCL_SUCCESS;
2792 0 : }
2793 :
2794 : HcclResult
2795 0 : TransportIbverbs::WriteAsync(struct Transport::Buffer& remoteBuf, struct Transport::Buffer& localBuf, Stream& stream)
2796 : {
2797 0 : struct WrAuxInfo aux = {};
2798 0 : return WriteCommon(remoteBuf.addr, localBuf.addr, remoteBuf.size, stream, WqeType::WQE_TYPE_DATA, aux);
2799 : }
2800 :
2801 0 : HcclResult TransportIbverbs::WriteReduceAsync(
2802 : struct Transport::Buffer& remoteBuf, struct Transport::Buffer& localBuf, const HcclDataType datatype,
2803 : HcclReduceOp redOp, Stream& stream)
2804 : {
2805 0 : struct WrAuxInfo aux = {};
2806 0 : aux.dataType = RDMA_REDUCE_DATA_TYPE_TABLE[datatype];
2807 0 : aux.reduceType = RDMA_REDUCE_OP_TYPE_TABLE[redOp];
2808 0 : if (aux.dataType == static_cast<uint8_t>(RdmaReduceDataType::RDMA_REDUCE_DATA_INVALID)
2809 0 : || aux.reduceType == static_cast<uint8_t>(RdmaReduceOpType::RDMA_REDUCE_OP_INVALID)) {
2810 0 : HCCL_ERROR(
2811 : "unsupported data type [%s] or Reduce type [%s]", GetDataTypeEnumStr(datatype).c_str(),
2812 : GetReduceOpEnumStr(redOp).c_str());
2813 0 : return HCCL_E_INTERNAL;
2814 : }
2815 :
2816 0 : return WriteCommon(remoteBuf.addr, localBuf.addr, remoteBuf.size, stream, WqeType::WQE_TYPE_DATA_WITH_REDUCE, aux);
2817 : }
2818 :
2819 0 : HcclResult TransportIbverbs::WriteSync(
2820 : [[maybe_unused]] struct Transport::Buffer& remoteBuf, [[maybe_unused]] struct Transport::Buffer& localBuf,
2821 : [[maybe_unused]] Stream& stream)
2822 : {
2823 0 : return HCCL_E_NOT_SUPPORT;
2824 : }
2825 :
2826 : HcclResult
2827 0 : TransportIbverbs::ReadAsync(struct Transport::Buffer& localBuf, struct Transport::Buffer& remoteBuf, Stream& stream)
2828 : {
2829 0 : struct WrAuxInfo aux = {};
2830 0 : return WriteCommon(remoteBuf.addr, localBuf.addr, remoteBuf.size, stream, WqeType::WQE_TYPE_READ_DATA, aux);
2831 : }
2832 :
2833 0 : HcclResult TransportIbverbs::ReadSync(
2834 : [[maybe_unused]] struct Transport::Buffer& localBuf, [[maybe_unused]] struct Transport::Buffer& remoteBuf,
2835 : [[maybe_unused]] Stream& stream)
2836 : {
2837 0 : return HCCL_E_NOT_SUPPORT;
2838 : }
2839 :
2840 0 : HcclResult TransportIbverbs::GetLocalNotify(std::vector<HcclSignalInfo>& localNotify)
2841 : {
2842 : HcclSignalInfo notifyInfo;
2843 0 : CHK_SMART_PTR_NULL(dataNotify_);
2844 0 : CHK_RET(dataNotify_->GetNotifyData(notifyInfo));
2845 0 : localNotify.push_back(notifyInfo);
2846 :
2847 0 : CHK_SMART_PTR_NULL(ackNotify_);
2848 0 : CHK_RET(ackNotify_->GetNotifyData(notifyInfo));
2849 0 : localNotify.push_back(notifyInfo);
2850 :
2851 0 : CHK_SMART_PTR_NULL(dataAckNotify_);
2852 0 : CHK_RET(dataAckNotify_->GetNotifyData(notifyInfo));
2853 0 : localNotify.push_back(notifyInfo);
2854 :
2855 : // 提取新增的notify资源
2856 0 : for (u32 i = 0; i < qpsPerConnection_; i++) {
2857 0 : for (u32 j = 0; j < notifyNum_; j++) {
2858 0 : CHK_SMART_PTR_NULL(userMultiQpLocalNotify_[i][j]);
2859 0 : CHK_RET(userMultiQpLocalNotify_[i][j]->GetNotifyData(notifyInfo));
2860 0 : localNotify.push_back(notifyInfo);
2861 : }
2862 : }
2863 :
2864 0 : return HCCL_SUCCESS;
2865 : }
2866 :
2867 14 : HcclResult TransportIbverbs::GetTransportErrorCqe(
2868 : const HcclNetDevCtx netDevCtx, std::vector<std::pair<TransportBase*, CqeInfo>>& infos, u32& num)
2869 : {
2870 14 : if (g_qpn2IbversLinkMap_.Size() == 0) {
2871 14 : num = 0;
2872 14 : return HCCL_SUCCESS;
2873 : }
2874 :
2875 0 : if (UNLIKELY(!g_flag)) {
2876 0 : CHK_RET(IsSuppCqeErrInfoListConfig(g_isSupCqeErrInfoListConfig));
2877 0 : g_flag = true;
2878 : }
2879 :
2880 0 : CHK_PTR_NULL(netDevCtx);
2881 0 : s32 deviceLogicId = (static_cast<NetDevContext*>(netDevCtx))->GetLogicId();
2882 0 : s32 devicePhyId = (static_cast<NetDevContext*>(netDevCtx))->GetPhyId();
2883 0 : HcclIpAddress localIp = (static_cast<NetDevContext*>(netDevCtx))->GetLocalIp();
2884 0 : NicType nicType = (static_cast<NetDevContext*>(netDevCtx))->GetNicType();
2885 0 : CHK_PRT_RET(
2886 : nicType == NicType::HOST_NIC_TYPE,
2887 : HCCL_WARNING("[TransportIbverbs][GetTransportErrorCqe] nicType[%d] not support", nicType), HCCL_SUCCESS);
2888 0 : RaResourceInfo raResourceInfo;
2889 0 : CHK_RET(NetworkManager::GetInstance(deviceLogicId).GetRaResourceInfo(raResourceInfo));
2890 0 : RdmaHandle rdmaHandle = raResourceInfo.nicSocketMap[localIp].nicRdmaHandle;
2891 0 : CHK_PTR_NULL(rdmaHandle);
2892 :
2893 0 : if (g_isSupCqeErrInfoListConfig) {
2894 0 : u32 loop = 0;
2895 0 : if (num > CQE_ARRAY_SIZE) {
2896 0 : loop = (num % CQE_ARRAY_SIZE) ? (num / CQE_ARRAY_SIZE) : ((num / CQE_ARRAY_SIZE) - 1);
2897 : }
2898 :
2899 0 : struct CqeErrInfo infolist[CQE_ARRAY_SIZE] = {};
2900 0 : u32 cqeNum = CQE_ARRAY_SIZE;
2901 0 : for (u32 index = 0; index <= loop; index++) {
2902 0 : cqeNum = (index == loop) ? (num - index * CQE_ARRAY_SIZE) : CQE_ARRAY_SIZE;
2903 0 : u32 temNum = cqeNum;
2904 0 : CHK_RET(hrtRaGetCqeErrInfoList(rdmaHandle, infolist, &temNum));
2905 0 : ProcessCqeInfo(devicePhyId, infolist, temNum, infos);
2906 0 : if (temNum < cqeNum) {
2907 0 : break;
2908 : }
2909 : }
2910 : } else {
2911 0 : struct CqeErrInfo infolist[1] = {};
2912 0 : CHK_RET(hrtRaGetCqeErrInfo(devicePhyId, &infolist[0]));
2913 0 : if (infolist[0].status == 0) {
2914 0 : num = 0;
2915 0 : return HCCL_SUCCESS;
2916 : }
2917 0 : u32 cqeNum = 1;
2918 0 : ProcessCqeInfo(devicePhyId, infolist, cqeNum, infos);
2919 : }
2920 :
2921 0 : num = infos.size();
2922 :
2923 0 : return HCCL_SUCCESS;
2924 0 : }
2925 :
2926 0 : void TransportIbverbs::ProcessCqeInfo(
2927 : const s32 deviceId, const struct CqeErrInfo* infolist, const u32 cqeNum,
2928 : std::vector<std::pair<TransportBase*, CqeInfo>>& infos)
2929 : {
2930 0 : for (u32 i = 0; i < cqeNum; i++) {
2931 : // localPhyId + qpn
2932 0 : auto it = g_qpn2IbversLinkMap_.Find(((static_cast<u64>(deviceId) << DEV_PHY_ID_BIT) | infolist[i].qpn));
2933 0 : if (it.second) {
2934 0 : TransportBase* ptr = reinterpret_cast<TransportBase*>(it.first->second);
2935 0 : infos.push_back(
2936 0 : std::make_pair(ptr, CqeInfo(infolist[i].time, infolist[i].status, it.first->second->GetRemoteIp())));
2937 0 : cqeErrQpn_ = infolist[i].qpn;
2938 : } else {
2939 0 : HCCL_RUN_WARNING("[GetTransportErrorCqe]get err failed, transport is not find.");
2940 : }
2941 : }
2942 0 : return;
2943 : }
2944 :
2945 0 : HcclIpAddress& TransportIbverbs::GetRemoteIp() { return machinePara_.remoteIpAddr; }
2946 :
2947 0 : HcclResult TransportIbverbs::GetTransportId(u32& id)
2948 : {
2949 0 : id = cqeErrQpn_;
2950 0 : return HCCL_SUCCESS;
2951 : }
2952 :
2953 0 : HcclResult TransportIbverbs::ExchangeCapabilityHybrid()
2954 : {
2955 0 : HCCL_INFO("[Hybrid][TransportIbverbs] Starting capability exchange");
2956 :
2957 : // 1. 构造本地能力信息(使用公共头文件中的默认值)
2958 : using namespace hcomm;
2959 : RoCECapability localCap;
2960 0 : localCap.InitDefaults();
2961 0 : localCap.nicDeploy = NICDeployment::NIC_DEPLOYMENT_DEVICE;
2962 0 : localCap.commStack = CommStackType::COMM_STACK_TRANSPORT_IBVERBS;
2963 :
2964 : // 2. 发送本地能力(合并为单次发送:totalLength已包含结构体大小)
2965 0 : CHK_RET(defaultSocket_->Send(&localCap, sizeof(localCap)));
2966 0 : HCCL_INFO("[Hybrid][TransportIbverbs] Sent capability, version=%u", localCap.version);
2967 :
2968 : // 3. 接收对端能力(单次接收)
2969 : RoCECapability recvCap;
2970 0 : CHK_RET(defaultSocket_->Recv(&recvCap, sizeof(recvCap)));
2971 :
2972 : // 4. 先检查魔数,如果不对可能是旧版本,需要回退
2973 0 : if (!RoCECapability::CheckMagic(reinterpret_cast<uint8_t*>(&recvCap), sizeof(recvCap))) {
2974 0 : HCCL_WARNING("[Hybrid][TransportIbverbs] Magic mismatch, peer may be old version. "
2975 : "Falling back to native mode.");
2976 : // 回退到原生模式
2977 0 : isHybridMode_ = false;
2978 0 : return HCCL_SUCCESS;
2979 : }
2980 :
2981 : // 5. 魔数正确,解析对端能力
2982 : RoCECapability remoteCap;
2983 0 : if (!remoteCap.Deserialize(reinterpret_cast<uint8_t*>(&recvCap), sizeof(recvCap))) {
2984 0 : HCCL_ERROR("[Hybrid][TransportIbverbs] Failed to deserialize capability");
2985 0 : return HCCL_E_PARA;
2986 : }
2987 :
2988 : // 6. 校验字段有效性
2989 0 : if (!remoteCap.Validate()) {
2990 0 : HCCL_ERROR("[Hybrid][TransportIbverbs] Capability validation failed");
2991 0 : return HCCL_E_INTERNAL;
2992 : }
2993 :
2994 : // 7. 版本兼容性处理(高版本兼容低版本)
2995 0 : if (remoteCap.version > ROCE_CAPABILITY_VERSION) {
2996 : // 对端版本更高,使用本地版本的功能集(最小公分母)
2997 0 : HCCL_INFO(
2998 : "[Hybrid][TransportIbverbs] Remote version %u > local %u, using local version features", remoteCap.version,
2999 : ROCE_CAPABILITY_VERSION);
3000 0 : } else if (remoteCap.version < ROCE_CAPABILITY_VERSION) {
3001 : // 对端版本更低,使用对端版本的功能集(向下兼容)
3002 0 : HCCL_INFO(
3003 : "[Hybrid][TransportIbverbs] Remote version %u < local %u, using remote version features", remoteCap.version,
3004 : ROCE_CAPABILITY_VERSION);
3005 : }
3006 :
3007 0 : isHybridMode_ = (remoteCap.commStack == CommStackType::COMM_STACK_HOST_CPU_ROCE) ? true : false;
3008 0 : HCCL_INFO(
3009 : "[Hybrid][TransportIbverbs]Exchange mode success, Remote is %s",
3010 : isHybridMode_ ? "HostCpuRoceChannel" : "TransportIbverbs");
3011 :
3012 0 : return HCCL_SUCCESS;
3013 : }
3014 :
3015 0 : HcclResult TransportIbverbs::GetDrainRemSrcMem(void*& remoteAddr, uint32_t& remoteKey, uint32_t& size)
3016 : {
3017 0 : auto opType = static_cast<u32>(MemType::NOTIFY_SRC_MEM);
3018 0 : remoteAddr = remoteMemMsg_[opType].addr;
3019 0 : remoteKey = remoteMemMsg_[opType].lkey;
3020 0 : size = remoteMemMsg_[opType].len;
3021 0 : return HCCL_SUCCESS;
3022 : }
3023 :
3024 1 : HcclResult TransportIbverbs::Drain(Stream& stream)
3025 : {
3026 1 : auto remoteType = static_cast<u32>(MemType::NOTIFY_SRC_MEM);
3027 1 : auto localType = static_cast<u32>(MemType::DATA_NOTIFY_MEM);
3028 1 : CHK_PTR_NULL(memMsg_[localType].addr);
3029 1 : CHK_PTR_NULL(remoteMemMsg_[remoteType].addr);
3030 1 : CHK_RET(Fence());
3031 1 : std::vector<WqeInfo> wqeInfoVec;
3032 1 : WrAuxInfo aux = {};
3033 1 : CHK_RET(AddWqeList(
3034 : remoteMemMsg_[remoteType].addr, memMsg_[localType].addr, memMsg_[localType].len, WqeType::WQE_TYPE_READ_DATA,
3035 : aux, wqeInfoVec));
3036 1 : CHK_RET(RdmaSendAsync(wqeInfoVec, stream, false));
3037 0 : CHK_SMART_PTR_NULL(dataNotify_);
3038 0 : CHK_RET(LocalIpcNotify::Wait(
3039 : stream, dispatcher_, dataNotify_, INVALID_VALUE_STAGE, NOTIFY_INVALID_WAIT_TIME, machinePara_.localUserrank,
3040 : machinePara_.remoteWorldRank));
3041 0 : return HCCL_SUCCESS;
3042 1 : }
3043 :
3044 0 : HcclResult TransportIbverbs::GetDrainLocalDataNotify(void*& localAddr, uint32_t& lkey, HcclSignalInfo& dataNotify)
3045 : {
3046 0 : localAddr = memMsg_[DATA_NOTIFY_MEM].addr;
3047 0 : lkey = memMsg_[DATA_NOTIFY_MEM].lkey;
3048 0 : CHK_SMART_PTR_NULL(dataNotify_);
3049 0 : CHK_RET(dataNotify_->GetNotifyData(dataNotify));
3050 0 : return HCCL_SUCCESS;
3051 : }
3052 : } // namespace hccl
|