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 "hdc.h"
12 : #include <chrono>
13 : #include "log.h"
14 : #include "ascend_hal.h"
15 : #include "orion_adapter_rts.h"
16 :
17 : namespace Hccl {
18 :
19 117 : HDCommunicate::HDCommunicate(u32 deviceLogicId, u32 flag, u32 buffLen)
20 117 : : deviceLogicId(deviceLogicId),
21 117 : flag(flag),
22 117 : buffLen(buffLen)
23 117 : {}
24 :
25 117 : HDCommunicate::~HDCommunicate()
26 : {
27 351 : HCCL_INFO("[~HDCommunicate]start hdc destroy");
28 117 : if ((devMem->GetAddr() != 0) && supportDevMemReg) {
29 2 : (void)halHostUnregister(reinterpret_cast<void*>(devMem->GetAddr()), deviceLogicId);
30 : }
31 117 : }
32 :
33 : // 在device中申请共享内存,其数据格式如下所示:
34 : // +---------------------+
35 : // | |
36 : // | content |
37 : // | |
38 : // +---------------------+
39 : // | head_cnt[u32] |
40 : // +---------------------+
41 : // | tail_cnt[u32] |
42 : // +---------------------+
43 : // 发送方更新content前,需要将head_cnt加1,更新数据后需要将tail_cnt加1;
44 : // 接收方在读取数据前判断共享内存中的tail_cnt和本地cache中的tailcnt是否一致,如不一致则需要更新本地cache;
45 : // 更新本地cache时,需要确保cache中head_cnt和tail_cnt一致,否则舍弃本次数据,继续更新cache直至一致;
46 :
47 : constexpr u32 HCCL_SHM_ALIGN = 4096;
48 : constexpr u32 HCCL_HDC_CONTROL_WORDS = 2;
49 : constexpr u32 HCCL_HDC_HEAD_POS = 2;
50 : constexpr u32 HCCL_HDC_TAIL_POS = 1;
51 :
52 9622389 : inline u32* HcclHdcGetControlWordAddr(void* base, u64 size, u32 pos)
53 : {
54 9622389 : return reinterpret_cast<u32*>(reinterpret_cast<u8*>((base)) + size - pos * sizeof(pos));
55 : }
56 :
57 115 : HcclResult HDCommunicate::Init()
58 : {
59 115 : CHK_RET(VerifyDeviceMemoryRegisterSupport());
60 :
61 115 : CHK_RET(AllocShm());
62 115 : CHK_RET(AllocReadCache());
63 :
64 : headCntAddr
65 115 : = HcclHdcGetControlWordAddr(reinterpret_cast<void*>(hostMem->GetAddr()), hostMem->GetSize(), HCCL_HDC_HEAD_POS);
66 : tailCntAddr
67 115 : = HcclHdcGetControlWordAddr(reinterpret_cast<void*>(hostMem->GetAddr()), hostMem->GetSize(), HCCL_HDC_TAIL_POS);
68 :
69 : devHeadCntAddr
70 115 : = HcclHdcGetControlWordAddr(reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), HCCL_HDC_HEAD_POS);
71 : devTailCntAddr
72 115 : = HcclHdcGetControlWordAddr(reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), HCCL_HDC_TAIL_POS);
73 345 : HCCL_INFO(
74 : "[HDCommunicate][Init] buffLen=%u, flag=%u, readCacheAddr=%p, devHeadCntAddr=%p, devTailCntAddr=%p", buffLen,
75 : flag, readCacheAddr, devHeadCntAddr, devTailCntAddr);
76 115 : return HCCL_SUCCESS;
77 : }
78 :
79 115 : HcclResult HDCommunicate::VerifyDeviceMemoryRegisterSupport()
80 : {
81 115 : supportDevMemReg = false;
82 115 : size_t outputLen = 0;
83 115 : struct supportFeaturePara input = {};
84 115 : struct supportFeaturePara output = {};
85 115 : s32 deviceId = HrtGetDevice();
86 115 : s32 logicDevId = 0;
87 : // 调用驱动接口前需将userDevId转换为logicDevId
88 115 : CHK_RET(HrtGetLogicDevIdByUserDevId(deviceId, logicDevId));
89 115 : deviceLogicId = static_cast<u32>(logicDevId);
90 115 : input.support_feature = CTRL_SUPPORT_PCIE_BAR_MEM_MASK;
91 115 : input.devid = static_cast<unsigned int>(logicDevId);
92 115 : halMemCtl(CTRL_TYPE_SUPPORT_FEATURE, &input, sizeof(struct supportFeaturePara), &output, &outputLen);
93 :
94 115 : if ((output.support_feature & CTRL_SUPPORT_PCIE_BAR_MEM_MASK) != 0) {
95 0 : supportDevMemReg = true;
96 : }
97 345 : HCCL_INFO("[HDCommunicate]supportDevMemReg[%d]", supportDevMemReg);
98 115 : return HCCL_SUCCESS;
99 : }
100 :
101 33 : struct HDCommunicateParams HDCommunicate::GetCommunicateParams() const
102 : {
103 33 : struct HDCommunicateParams params;
104 33 : params.hostAddr = reinterpret_cast<u64>(reinterpret_cast<void*>(hostMem->GetAddr()));
105 33 : params.deviceAddr = reinterpret_cast<u64>(reinterpret_cast<void*>(devMem->GetAddr()));
106 33 : params.readCacheAddr = reinterpret_cast<u64>(readCacheAddr);
107 33 : params.devMemSize = devMem->GetSize();
108 33 : params.buffLen = buffLen;
109 33 : params.flag = flag;
110 33 : return params;
111 : }
112 : // 为了按照调用顺序执行,防止编译器优化导致产生异常行为
113 : #pragma GCC push_options
114 : #pragma GCC optimize("O0")
115 15 : HcclResult HDCommunicate::Put(u32 offset, u32 length, u8* value)
116 : {
117 15 : if (length == 0) {
118 0 : return HCCL_SUCCESS;
119 : }
120 15 : CHK_PTR_NULL(value);
121 :
122 15 : if (flag == HCCLV2_HDC_TYPE_D2H) {
123 0 : HCCL_ERROR("[HDCommunicate][Put]Invalid usage, flag=%u", flag);
124 0 : return HCCL_E_PARA;
125 : }
126 15 : CHK_PRT_RET(
127 : (offset + length > buffLen),
128 : HCCL_ERROR("[HDCommunicate][Put]Invalid length, offset=%u, length=%u", offset, length), HCCL_E_PARA);
129 15 : std::lock_guard<std::mutex> lock(shmLock);
130 15 : return Write(offset, length, value);
131 15 : }
132 :
133 4800905 : HcclResult HDCommunicate::Get(u32 offset, u32 length, u8* value)
134 : {
135 4800905 : if (length == 0) {
136 0 : return HCCL_SUCCESS;
137 : }
138 4800905 : CHK_PTR_NULL(value);
139 4800905 : CHK_PRT_RET(
140 : (offset + length > buffLen),
141 : HCCL_ERROR("[HDCommunicate][Get]Invalid length, offset=%u, length=%u, befferLen=%u", offset, length, buffLen),
142 : HCCL_E_PARA);
143 4800905 : std::lock_guard<std::mutex> lock(shmLock);
144 4800905 : return Read(offset, length, value);
145 4800905 : }
146 :
147 0 : HcclResult HrtDrvMemCpy(void* dst, uint64_t destMax, const void* src, uint64_t count)
148 : {
149 : // 参数有效性检查
150 0 : CHK_PTR_NULL(dst);
151 0 : CHK_PTR_NULL(src);
152 :
153 0 : uint64_t dstAddr = reinterpret_cast<uintptr_t>(dst);
154 0 : uint64_t srcAddr = reinterpret_cast<uintptr_t>(const_cast<void*>(src));
155 0 : drvError_t ret = drvMemcpy(dstAddr, destMax, srcAddr, count);
156 0 : CHK_PRT_RET(
157 : ret != DRV_ERROR_NONE,
158 : HCCL_ERROR(
159 : "errNo[0x%016llx] hrtDrvMemCpy fail,"
160 : "return[%d].",
161 : HCCL_ERROR_CODE(HCCL_E_DRV), ret),
162 : HCCL_E_DRV);
163 :
164 0 : return HCCL_SUCCESS;
165 : }
166 :
167 15 : HcclResult HDCommunicate::Write(u32 offset, u32 length, u8* value)
168 : {
169 15 : if (length == 0) {
170 0 : return HCCL_SUCCESS;
171 : }
172 15 : CHK_PTR_NULL(value);
173 :
174 15 : u32 head = *headCntAddr;
175 15 : head++;
176 15 : *headCntAddr = head;
177 15 : if (!supportDevMemReg) {
178 15 : CHK_RET(HrtDrvMemCpy(devHeadCntAddr, sizeof(u32), headCntAddr, sizeof(u32)));
179 : }
180 :
181 60 : auto ret = memcpy_s(
182 15 : reinterpret_cast<u8*>(hostMem->GetAddr()) + offset, hostMem->GetSize() - HCCL_HDC_CONTROL_WORDS * sizeof(u32),
183 : value, length);
184 15 : CHK_PRT_RET(ret != EOK, HCCL_ERROR("[HDCommunicate][Write]memcpy_s failed, return[%d].", ret), HCCL_E_INTERNAL);
185 :
186 15 : if (!supportDevMemReg) {
187 15 : CHK_RET(HrtDrvMemCpy(
188 : reinterpret_cast<u8*>(devMem->GetAddr()) + offset,
189 : hostMem->GetSize() - HCCL_HDC_CONTROL_WORDS * sizeof(u32), value, length));
190 : }
191 :
192 15 : u32 tail = *tailCntAddr;
193 15 : tail++;
194 15 : *tailCntAddr = tail;
195 15 : if (!supportDevMemReg) {
196 15 : CHK_RET(HrtDrvMemCpy(devTailCntAddr, sizeof(u32), tailCntAddr, sizeof(u32)));
197 : }
198 15 : return HCCL_SUCCESS;
199 : }
200 :
201 4800905 : HcclResult HDCommunicate::Read(u32 offset, u32 length, u8* value)
202 : {
203 4800905 : if (length == 0) {
204 0 : return HCCL_SUCCESS;
205 : }
206 4800905 : CHK_PTR_NULL(value);
207 4800905 : u32* cachedTailCntAddr = HcclHdcGetControlWordAddr(readCacheAddr, devMem->GetSize(), HCCL_HDC_TAIL_POS);
208 4800905 : volatile u32 cachedTailCnt = *cachedTailCntAddr;
209 4800905 : volatile u32 tailCnt = 0;
210 4800905 : if (!supportDevMemReg) {
211 4800905 : u32 tempTailCnt = 0;
212 4800905 : u32* devSrcTailCntAddr = HcclHdcGetControlWordAddr(
213 4800905 : reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), HCCL_HDC_TAIL_POS);
214 4800905 : CHK_RET(HrtDrvMemCpy(&tempTailCnt, sizeof(u32), devSrcTailCntAddr, sizeof(u32)));
215 4800905 : tailCnt = tempTailCnt;
216 : } else {
217 0 : tailCnt = *tailCntAddr;
218 : }
219 4800905 : if (cachedTailCnt != tailCnt) {
220 : // 默认HDC超时时间为10s
221 11 : CHK_RET(UpdateCache(10));
222 : }
223 4800905 : auto ret = memcpy_s(value, length, static_cast<u8*>(readCacheAddr) + offset, length);
224 4800905 : CHK_PRT_RET(ret != EOK, HCCL_ERROR("[HDCommunicate][Read]memcpy_s failed, return[%d].", ret), HCCL_E_INTERNAL);
225 4800905 : return HCCL_SUCCESS;
226 : }
227 :
228 11 : HcclResult HDCommunicate::UpdateCache(u32 timeoutSec)
229 : {
230 11 : void* srcBaseAddr = reinterpret_cast<void*>(hostMem->GetAddr());
231 11 : u32* srcHeadCntAddr = HcclHdcGetControlWordAddr(srcBaseAddr, devMem->GetSize(), HCCL_HDC_HEAD_POS);
232 11 : u32* srcTailCntAddr = HcclHdcGetControlWordAddr(srcBaseAddr, devMem->GetSize(), HCCL_HDC_TAIL_POS);
233 : u32* devSrcHeadCntAddr
234 11 : = HcclHdcGetControlWordAddr(reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), HCCL_HDC_HEAD_POS);
235 : u32* devSrcTailCntAddr
236 11 : = HcclHdcGetControlWordAddr(reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), HCCL_HDC_TAIL_POS);
237 11 : u32* cachedHeadCntAddr = HcclHdcGetControlWordAddr(readCacheAddr, devMem->GetSize(), HCCL_HDC_HEAD_POS);
238 11 : u32* cachedTailCntAddr = HcclHdcGetControlWordAddr(readCacheAddr, devMem->GetSize(), HCCL_HDC_TAIL_POS);
239 :
240 11 : s32 ret = 0;
241 11 : auto startTime = std::chrono::steady_clock::now();
242 11 : auto timeout = std::chrono::seconds(timeoutSec);
243 : while (1) {
244 11 : if (!supportDevMemReg) {
245 : // step1: cache尾计数
246 11 : CHK_RET(HrtDrvMemCpy(cachedTailCntAddr, sizeof(u32), devSrcTailCntAddr, sizeof(u32)));
247 :
248 : // step2: cache数据
249 11 : CHK_RET(HrtDrvMemCpy(
250 : readCacheAddr, devMem->GetSize() - HCCL_HDC_CONTROL_WORDS * sizeof(u32),
251 : reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize() - HCCL_HDC_CONTROL_WORDS * sizeof(u32)));
252 :
253 : // step3:cache头计数
254 11 : CHK_RET(HrtDrvMemCpy(cachedHeadCntAddr, sizeof(u32), devSrcHeadCntAddr, sizeof(u32)));
255 : } else {
256 : // step1: cache尾计数
257 0 : ret = memcpy_s(cachedTailCntAddr, sizeof(u32), srcTailCntAddr, sizeof(u32));
258 0 : CHK_PRT_RET(
259 : ret != EOK, HCCL_ERROR("[HDCommunicate][UpdateCache]memcpy_s failed, return[%d].", ret),
260 : HCCL_E_INTERNAL);
261 :
262 : // step2: cache数据
263 0 : ret = memcpy_s(
264 0 : readCacheAddr, devMem->GetSize() - HCCL_HDC_CONTROL_WORDS * sizeof(u32), srcBaseAddr,
265 0 : devMem->GetSize() - HCCL_HDC_CONTROL_WORDS * sizeof(u32));
266 0 : CHK_PRT_RET(
267 : ret != EOK, HCCL_ERROR("[HDCommunicate][UpdateCache]memcpy_s failed, return[%d].", ret),
268 : HCCL_E_INTERNAL);
269 :
270 : // step3:cache头计数
271 0 : ret = memcpy_s(cachedHeadCntAddr, sizeof(u32), srcHeadCntAddr, sizeof(u32));
272 0 : CHK_PRT_RET(
273 : ret != EOK, HCCL_ERROR("[HDCommunicate][UpdateCache]memcpy_s failed, return[%d].", ret),
274 : HCCL_E_INTERNAL);
275 : }
276 :
277 11 : volatile u32 cachedHeadCnt = *cachedHeadCntAddr;
278 11 : volatile u32 cachedTailCnt = *cachedTailCntAddr;
279 :
280 11 : if (cachedHeadCnt == cachedTailCnt) {
281 11 : break;
282 : }
283 0 : CHK_PRT_RET(
284 : ((std::chrono::steady_clock::now() - startTime) >= timeout),
285 : HCCL_WARNING("[HDCommunicate][UpdateCache]get remote data timeout[%u s].", timeoutSec), HCCL_E_AGAIN);
286 0 : }
287 11 : return HCCL_SUCCESS;
288 : }
289 : #pragma GCC pop_options
290 :
291 115 : HcclResult HDCommunicate::AllocShm()
292 : {
293 : // 共享内存size需要按照4K(4*1024=4096)对齐
294 115 : size_t size
295 115 : = (buffLen + HCCL_HDC_CONTROL_WORDS * sizeof(u32) + HCCL_SHM_ALIGN - 1) / HCCL_SHM_ALIGN * HCCL_SHM_ALIGN;
296 115 : devMem = std::make_unique<DevBuffer>(size);
297 115 : HrtMemset(reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), devMem->GetSize());
298 :
299 115 : if (supportDevMemReg) {
300 0 : void* hostAddr = nullptr;
301 0 : halHostRegister(
302 0 : reinterpret_cast<void*>(devMem->GetAddr()), devMem->GetSize(), DEV_SVM_MAP_HOST, deviceLogicId, &hostAddr);
303 :
304 0 : hostMem = std::make_unique<HostBuffer>(reinterpret_cast<uintptr_t>(hostAddr), devMem->GetSize());
305 : } else {
306 115 : hostMem = std::make_unique<HostBuffer>(devMem->GetSize());
307 : }
308 :
309 115 : auto ret = memset_s(reinterpret_cast<void*>(hostMem->GetAddr()), hostMem->GetSize(), 0, hostMem->GetSize());
310 115 : CHK_PRT_RET(ret != EOK, HCCL_ERROR("[HDCommunicate][AllocShm]memset_s failed, return[%d].", ret), HCCL_E_INTERNAL);
311 :
312 115 : return HCCL_SUCCESS;
313 : }
314 :
315 115 : HcclResult HDCommunicate::AllocReadCache()
316 : {
317 115 : if (flag == HCCLV2_HDC_TYPE_D2H) {
318 57 : hostCache = std::make_unique<HostBuffer>(hostMem->GetSize());
319 : auto ret
320 57 : = memset_s(reinterpret_cast<void*>(hostCache->GetAddr()), hostCache->GetSize(), 0, hostCache->GetSize());
321 57 : CHK_PRT_RET(
322 : ret != EOK, HCCL_ERROR("[HDCommunicate][AllocReadCache]memset_s failed, return[%d].", ret),
323 : HCCL_E_INTERNAL);
324 57 : readCacheAddr = reinterpret_cast<void*>(hostCache->GetAddr());
325 : } else {
326 58 : devCache = std::make_unique<DevBuffer>(devMem->GetSize());
327 58 : HrtMemset(reinterpret_cast<void*>(devCache->GetAddr()), devCache->GetSize(), devCache->GetSize());
328 58 : readCacheAddr = reinterpret_cast<void*>(devCache->GetAddr());
329 : }
330 115 : return HCCL_SUCCESS;
331 : }
332 : } // namespace Hccl
|