LCOV - code coverage report
Current view: top level - legacy/ascend950/framework/communicator - hdc.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 82.0 % 167 137
Test Date: 2026-08-18 17:47:01 Functions: 92.9 % 14 13

            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
        

Generated by: LCOV version 2.0-1