| @@ -25,19 +25,25 @@ | |||
| 25 | namespace AscendC { | 25 | namespace AscendC { |
| 26 | namespace ccu { | 26 | namespace ccu { |
| 27 | 27 | ||
| 28 | -// 主模板未实现:未特化的资源类型实例化 Array<T> 时编译失败, | ||
| 29 | -// 当前期次仅 Variable / Event / Buffer 提供底层 CcuBlock*Alloc C 接口。 | ||
| 30 | template <typename T> struct CcuArrayTraits; | 28 | template <typename T> struct CcuArrayTraits; |
| 31 | 29 | ||
| 32 | template <> struct CcuArrayTraits<Variable> { | 30 | template <> struct CcuArrayTraits<Variable> { |
| 33 | using Handle = CcuVariableHandle; | 31 | using Handle = CcuVariableHandle; |
| 34 | static CcuResult BlockAlloc(Handle* h, uint32_t n) { return CcuBlockVariableAlloc(h, n); } | 32 | static CcuResult BlockAlloc(Handle* h, uint32_t n) { return CcuBlockVariableAlloc(h, n); } |
| 33 | + static CcuResult CreateByAcquire(Handle acqHandle, uint32_t index, Handle* h) | ||
| 34 | + { | ||
| 35 | + return CcuVariableGetByIndex(acqHandle, index, h); | ||
| 36 | + } | ||
| 35 | static void SetHandle(Variable& v, Handle h) { v.handle = h; } | 37 | static void SetHandle(Variable& v, Handle h) { v.handle = h; } |
| 36 | }; | 38 | }; |
| 37 | 39 | ||
| 38 | template <> struct CcuArrayTraits<Event> { | 40 | template <> struct CcuArrayTraits<Event> { |
| 39 | using Handle = CcuEventHandle; | 41 | using Handle = CcuEventHandle; |
| 40 | static CcuResult BlockAlloc(Handle* h, uint32_t n) { return CcuBlockEventAlloc(h, n); } | 42 | static CcuResult BlockAlloc(Handle* h, uint32_t n) { return CcuBlockEventAlloc(h, n); } |
| 43 | + static CcuResult CreateByAcquire(Handle acqHandle, uint32_t index, Handle* h) | ||
| 44 | + { | ||
| 45 | + return CcuEventGetByIndex(acqHandle, index, h); | ||
| 46 | + } | ||
| 41 | static void SetHandle(Event& e, Handle h) { e.handle = h; } | 47 | static void SetHandle(Event& e, Handle h) { e.handle = h; } |
| 42 | }; | 48 | }; |
| 43 | 49 | ||
| @@ -47,8 +53,6 @@ template <> struct CcuArrayTraits<CcuBuffer> { | |||
| 47 | static void SetHandle(CcuBuffer& b, Handle h) { b.handle = h; } | 53 | static void SetHandle(CcuBuffer& b, Handle h) { b.handle = h; } |
| 48 | }; | 54 | }; |
| 49 | 55 | ||
| 50 | -// 连续资源容器:在构造时一次性 BlockAlloc 出 count 个底层句柄并填充给占位元素。 | ||
| 51 | -// 元素本身通过 NoAllocTag 私有构造跳过单元 Alloc,避免与 BlockAlloc 双重分配。 | ||
| 52 | template <typename T> | 56 | template <typename T> |
| 53 | class Array final { | 57 | class Array final { |
| 54 | public: | 58 | public: |
| @@ -77,6 +81,34 @@ public: | |||
| 77 | } | 81 | } |
| 78 | } | 82 | } |
| 79 | 83 | ||
| 84 | + Array(typename CcuArrayTraits<T>::Handle acqHandle, uint32_t count) : count_(count) { | ||
| 85 | + if (count == 0) { | ||
| 86 | + return; | ||
| 87 | + } | ||
| 88 | + using H = typename CcuArrayTraits<T>::Handle; | ||
| 89 | + elems_ = static_cast<T*>(::operator new(sizeof(T) * count)); | ||
| 90 | + for (uint32_t i = 0; i < count; ++i) { | ||
| 91 | + ::new (static_cast<void*>(&elems_[i])) T(detail::NoAllocTag{}); | ||
| 92 | + } | ||
| 93 | + for (uint32_t i = 0; i < count; ++i) { | ||
| 94 | + H handle{}; | ||
| 95 | + auto ret = CcuArrayTraits<T>::CreateByAcquire(acqHandle, i, &handle); | ||
| 96 | + if (ret != CcuResult::CCU_SUCCESS) { | ||
| 97 | + std::string errMsg = "Array creation failed at index " + std::to_string(i) + | ||
| 98 | + ", requested count=" + std::to_string(count) + | ||
| 99 | + "; the acquire handle likely holds fewer resources than count"; | ||
| 100 | + for (uint32_t j = 0; j < count; ++j) { | ||
| 101 | + elems_[j].~T(); | ||
| 102 | + } | ||
| 103 | + ::operator delete(elems_); | ||
| 104 | + elems_ = nullptr; | ||
| 105 | + count_ = 0; | ||
| 106 | + throw ::AscendC::ccu::detail::CcuException(ret, errMsg.c_str()); | ||
| 107 | + } | ||
| 108 | + CcuArrayTraits<T>::SetHandle(elems_[i], handle); | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + | ||
| 80 | ~Array() { | 112 | ~Array() { |
| 81 | if (elems_ == nullptr) { | 113 | if (elems_ == nullptr) { |
| 82 | return; | 114 | return; |
| @@ -29,6 +29,11 @@ public: | |||
| 29 | CCU_THROW_IF_FAILED(CcuEventAlloc(&this->handle),"CcuEventAlloc: failed"); | 29 | CCU_THROW_IF_FAILED(CcuEventAlloc(&this->handle),"CcuEventAlloc: failed"); |
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | + explicit Event(CcuEventHandle acqHandle, uint32_t index = 0) { | ||
| 33 | + CCU_THROW_IF_FAILED(CcuEventGetByIndex(acqHandle, index, &this->handle), | ||
| 34 | + "CcuEventGetByIndex: failed"); | ||
| 35 | + } | ||
| 36 | + | ||
| 32 | Event(const Event& other) : handle(other.handle) {} | 37 | Event(const Event& other) : handle(other.handle) {} |
| 33 | 38 | ||
| 34 | Event(Event&& other) noexcept : handle(other.handle) {} | 39 | Event(Event&& other) noexcept : handle(other.handle) {} |
| @@ -18,6 +18,51 @@ | |||
| 18 | extern "C" { | 18 | extern "C" { |
| 19 | #endif // __cplusplus | 19 | #endif // __cplusplus |
| 20 | 20 | ||
| 21 | +/** | ||
| 22 | + * @brief 在指定 CCU 实例上预约一段连续的 Variable(XN) 资源,并在申请期完成地址映射。 | ||
| 23 | + * @param[in] insHandle CCU 实例句柄,资源从该实例的资源池中切分。 | ||
| 24 | + * @param[in] dieId 资源归属的 ioDie ID,取值范围 [0, CCU_MAX_IODIE_NUM)。 | ||
| 25 | + * @param[in] num 预约的连续资源个数,须大于 0。 | ||
| 26 | + * @param[out] varHandle 预约句柄,不可为 nullptr;失败时置 0。 | ||
| 27 | + * @return CcuResult。CCU_E_PARA:dieId 或 num 非法;CCU_E_UNAVAIL:无满足 num 的连续块; | ||
| 28 | + * CCU_E_PTR:varHandle 为 nullptr;CCU_E_RUNTIME:地址映射失败。 | ||
| 29 | + * @note 句柄生命周期与 insHandle 绑定,无显式释放接口,由 HcommCcuInsDestroy 统一解映射并还池。 | ||
| 30 | + */ | ||
| 31 | +extern CcuResult HcommCcuVariableAlloc(CcuInsHandle insHandle, uint8_t dieId, uint32_t num, | ||
同步刷新代码仓中的接口资料 ![]() ![]() | |||
| 32 | + CcuVariableHandle *varHandle); | ||
| 33 | + | ||
| 34 | +/** | ||
| 35 | + * @brief 预约一段连续的 Event(CKE) 资源,参数与生命周期约束同 HcommCcuVariableAlloc。 | ||
| 36 | + * @param[in] insHandle CCU 实例句柄。 | ||
| 37 | + * @param[in] dieId 资源归属的 ioDie ID,取值范围 [0, CCU_MAX_IODIE_NUM)。 | ||
| 38 | + * @param[in] num 预约的连续资源个数,须大于 0。 | ||
| 39 | + * @param[out] eventHandle 预约句柄,不可为 nullptr;失败时置 0。 | ||
| 40 | + * @return CcuResult,错误码语义同 HcommCcuVariableAlloc。 | ||
| 41 | + * @note CKE 池与 kernel 自身的完成事件共用且单 die 容量有限,大 num 可能总量足够却无连续块。 | ||
| 42 | + */ | ||
| 43 | +extern CcuResult HcommCcuEventAlloc(CcuInsHandle insHandle, uint8_t dieId, uint32_t num, | ||
| 44 | + CcuEventHandle *eventHandle); | ||
| 45 | + | ||
| 46 | +/** | ||
| 47 | + * @brief 查询预约句柄名下第 index 个 Variable(XN) 的进程可访问虚拟地址。 | ||
| 48 | + * @param[in] varHandle HcommCcuVariableAlloc 返回的预约句柄。 | ||
| 49 | + * @param[in] index 预约段内序号,取值范围 [0, num)。 | ||
| 50 | + * @param[out] va 该资源的进程可访问虚拟地址,不可为 nullptr。 | ||
| 51 | + * @return CcuResult。CCU_E_NOT_FOUND:句柄不存在;CCU_E_PARA:句柄类型不符或 index 越界; | ||
| 52 | + * CCU_E_PTR:va 为 nullptr。 | ||
| 53 | + * @note 地址已在 Alloc 阶段映射并缓存,此处为纯查表;VA 供 CCU 外模块访问,有效期同句柄。 | ||
| 54 | + */ | ||
| 55 | +extern CcuResult HcommCcuVariableGetAddr(CcuVariableHandle varHandle, uint32_t index, uint64_t *va); | ||
| 56 | + | ||
| 57 | +/** | ||
| 58 | + * @brief 查询预约句柄名下第 index 个 Event(CKE) 的进程可访问虚拟地址。 | ||
| 59 | + * @param[in] eventHandle HcommCcuEventAlloc 返回的预约句柄。 | ||
| 60 | + * @param[in] index 预约段内序号,取值范围 [0, num)。 | ||
| 61 | + * @param[out] va 该资源的进程可访问虚拟地址,不可为 nullptr。 | ||
| 62 | + * @return CcuResult,错误码与约束同 HcommCcuVariableGetAddr。 | ||
| 63 | + */ | ||
| 64 | +extern CcuResult HcommCcuEventGetAddr(CcuEventHandle eventHandle, uint32_t index, uint64_t *va); | ||
| 65 | + | ||
| 21 | /** | 66 | /** |
| 22 | * @brief 创建 CCU 实例资源描述符 | 67 | * @brief 创建 CCU 实例资源描述符 |
| 23 | * @param[in] dieId IO Die 编号,取值范围 [0, CCU_MAX_IODIE_NUM) | 68 | * @param[in] dieId IO Die 编号,取值范围 [0, CCU_MAX_IODIE_NUM) |
| @@ -43,6 +43,11 @@ public: | |||
| 43 | "CcuVariableAlloc: failed"); | 43 | "CcuVariableAlloc: failed"); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | + explicit Variable(CcuVariableHandle varHandle, uint32_t index = 0) { | ||
| 47 | + CCU_THROW_IF_FAILED(CcuVariableGetByIndex(varHandle, index, &this->handle), | ||
| 48 | + "CcuVariableGetByIndex: failed"); | ||
| 49 | + } | ||
| 50 | + | ||
| 46 | Variable(const Variable& other) { | 51 | Variable(const Variable& other) { |
| 47 | this->handle = other.handle; | 52 | this->handle = other.handle; |
| 48 | } | 53 | } |
| @@ -41,6 +41,12 @@ extern CcuResult CcuBlockBufferAlloc(CcuBufferHandle *bufHandles, uint32_t count | |||
| 41 | extern CcuResult CcuVariableCreateByChannel(ChannelHandle channel, | 41 | extern CcuResult CcuVariableCreateByChannel(ChannelHandle channel, |
| 42 | uint32_t varIndex, CcuVariableHandle *varHandle); | 42 | uint32_t varIndex, CcuVariableHandle *varHandle); |
| 43 | 43 | ||
| 44 | +extern CcuResult CcuVariableGetByIndex(CcuVariableHandle acqHandle, | ||
| 45 | + uint32_t index, CcuVariableHandle *varHandle); | ||
| 46 | + | ||
| 47 | +extern CcuResult CcuEventGetByIndex(CcuEventHandle acqHandle, | ||
| 48 | + uint32_t index, CcuEventHandle *eventHandle); | ||
| 49 | + | ||
| 44 | //Variable操作类 相关接口 | 50 | //Variable操作类 相关接口 |
| 45 | extern CcuResult CcuVariableAssignImm(CcuVariableHandle resVar, uint64_t immediate); | 51 | extern CcuResult CcuVariableAssignImm(CcuVariableHandle resVar, uint64_t immediate); |
| 46 | extern CcuResult CcuVariableAssignVar(CcuVariableHandle dstVarHandle, CcuVariableHandle srcVarHandle); | 52 | extern CcuResult CcuVariableAssignVar(CcuVariableHandle dstVarHandle, CcuVariableHandle srcVarHandle); |
| @@ -25,6 +25,7 @@ | |||
| 25 | 25 | ||
| 26 | #include "ccu_kernel_mgr.h" | 26 | #include "ccu_kernel_mgr.h" |
| 27 | #include "ccu_instance_mgr.h" | 27 | #include "ccu_instance_mgr.h" |
| 28 | +#include "ccu_var_event_res_mgr.h" | ||
| 28 | 29 | ||
| 29 | #include "thread.h" | 30 | #include "thread.h" |
| 30 | 31 | ||
| @@ -328,6 +329,64 @@ CcuResult HcommCcuKernelLaunch(ThreadHandle threadHandle, | |||
| 328 | return CcuResult::CCU_SUCCESS; | 329 | return CcuResult::CCU_SUCCESS; |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 332 | +// 定位实例资源仓后转发给 CcuVarEventResMgr;预约、地址映射与失败回滚均由该类内部完成 | ||
| 333 | +static CcuResult CcuAllocVarEventRes(CcuInsHandle insHandle, hcomm::CcuVarEventType type, | ||
| 334 | + uint8_t dieId, uint32_t num, uint64_t &outHandle) | ||
| 335 | +{ | ||
| 336 | + const uint32_t devLogicId = HcclGetThreadDeviceId(); | ||
| 337 | + auto *ccuIns = hcomm::CcuInstanceMgr::GetInstance(devLogicId).Get(insHandle); | ||
| 338 | + CCU_CHK_PTR_NULL(ccuIns); | ||
| 339 | + | ||
| 340 | + auto *resPack = ccuIns->GetResPack(); | ||
| 341 | + CCU_CHK_PTR_NULL(resPack); | ||
| 342 | + | ||
| 343 | + CCU_CHK_RET(hcomm::CcuVarEventResMgr::GetInstance(devLogicId).Acquire( | ||
| 344 | + insHandle, resPack->GetCcuResRepo(), type, dieId, num, outHandle)); | ||
| 345 | + return CcuResult::CCU_SUCCESS; | ||
| 346 | +} | ||
| 347 | + | ||
| 348 | +CcuResult HcommCcuVariableAlloc(CcuInsHandle insHandle, uint8_t dieId, uint32_t num, | ||
| 349 | + CcuVariableHandle *varHandle) | ||
| 350 | +{ | ||
| 351 | + CCU_CHK_PTR_NULL(varHandle); | ||
| 352 | + *varHandle = 0; | ||
| 353 | + CCU_CHK_RET(CcuAllocVarEventRes(insHandle, hcomm::CcuVarEventType::VARIABLE, | ||
[LOW] HcommCcuVariableAlloc 未包裹异常处理 第 353 行: 问题分析:
建议修复: 用 CCU_EXCEPTION_HANDLE_BEGIN/END 包裹 CcuAllocVarEventRes 调用,失败时返回 CCU_E_INTERNAL。HcommCcuEventAlloc 同理。 ![]() ![]() | |||
| 354 | + dieId, num, *varHandle)); | ||
| 355 | + return CcuResult::CCU_SUCCESS; | ||
| 356 | +} | ||
| 357 | + | ||
| 358 | +CcuResult HcommCcuEventAlloc(CcuInsHandle insHandle, uint8_t dieId, uint32_t num, | ||
| 359 | + CcuEventHandle *eventHandle) | ||
| 360 | +{ | ||
| 361 | + CCU_CHK_PTR_NULL(eventHandle); | ||
| 362 | + *eventHandle = 0; | ||
| 363 | + CCU_CHK_RET(CcuAllocVarEventRes(insHandle, hcomm::CcuVarEventType::EVENT, | ||
| 364 | + dieId, num, *eventHandle)); | ||
| 365 | + return CcuResult::CCU_SUCCESS; | ||
| 366 | +} | ||
| 367 | + | ||
| 368 | +CcuResult HcommCcuVariableGetAddr(CcuVariableHandle varHandle, uint32_t index, uint64_t *va) | ||
| 369 | +{ | ||
| 370 | + CCU_CHK_PTR_NULL(va); | ||
| 371 | + | ||
| 372 | + const uint32_t devLogicId = HcclGetThreadDeviceId(); | ||
| 373 | + CCU_CHK_RET(hcomm::CcuVarEventResMgr::GetInstance(devLogicId).GetSavedAddr( | ||
| 374 | + hcomm::CcuVarEventType::VARIABLE, varHandle, index, *va)); | ||
| 375 | + | ||
| 376 | + return CcuResult::CCU_SUCCESS; | ||
| 377 | +} | ||
| 378 | + | ||
| 379 | +CcuResult HcommCcuEventGetAddr(CcuEventHandle eventHandle, uint32_t index, uint64_t *va) | ||
| 380 | +{ | ||
| 381 | + CCU_CHK_PTR_NULL(va); | ||
| 382 | + | ||
| 383 | + const uint32_t devLogicId = HcclGetThreadDeviceId(); | ||
| 384 | + CCU_CHK_RET(hcomm::CcuVarEventResMgr::GetInstance(devLogicId).GetSavedAddr( | ||
| 385 | + hcomm::CcuVarEventType::EVENT, eventHandle, index, *va)); | ||
| 386 | + | ||
| 387 | + return CcuResult::CCU_SUCCESS; | ||
| 388 | +} | ||
| 389 | + | ||
| 331 | CcuResult HcommCcuGetMemToken(uint64_t srcVa, uint64_t size, uint64_t *tokenInfo) | 390 | CcuResult HcommCcuGetMemToken(uint64_t srcVa, uint64_t size, uint64_t *tokenInfo) |
| 332 | { | 391 | { |
| 333 | CCU_CHK_PTR_NULL(tokenInfo); | 392 | CCU_CHK_PTR_NULL(tokenInfo); |
| @@ -127,6 +127,26 @@ CcuResult CcuVariableCreateByChannel(ChannelHandle channel, uint32_t varIndex, C | |||
| 127 | return CcuResult::CCU_SUCCESS; | 127 | return CcuResult::CCU_SUCCESS; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | +CcuResult CcuVariableGetByIndex(CcuVariableHandle acqHandle, uint32_t index, CcuVariableHandle *varHandle) | ||
| 131 | +{ | ||
| 132 | + CCU_CHK_PTR_NULL(varHandle); | ||
| 133 | + const uint32_t devLogicId = HcclGetThreadDeviceId(); | ||
| 134 | + auto kernel = hcomm::CcuKernelMgr::GetInstance(devLogicId).GetCurrentKernel(); | ||
| 135 | + CCU_CHK_PTR_NULL(kernel); | ||
| 136 | + CCU_CHK_RET(kernel->VariableCreateByAcquire(acqHandle, index, varHandle)); | ||
| 137 | + return CcuResult::CCU_SUCCESS; | ||
| 138 | +} | ||
| 139 | + | ||
| 140 | +CcuResult CcuEventGetByIndex(CcuEventHandle acqHandle, uint32_t index, CcuEventHandle *eventHandle) | ||
| 141 | +{ | ||
| 142 | + CCU_CHK_PTR_NULL(eventHandle); | ||
| 143 | + const uint32_t devLogicId = HcclGetThreadDeviceId(); | ||
| 144 | + auto kernel = hcomm::CcuKernelMgr::GetInstance(devLogicId).GetCurrentKernel(); | ||
| 145 | + CCU_CHK_PTR_NULL(kernel); | ||
| 146 | + CCU_CHK_RET(kernel->EventCreateByAcquire(acqHandle, index, eventHandle)); | ||
| 147 | + return CcuResult::CCU_SUCCESS; | ||
| 148 | +} | ||
| 149 | + | ||
| 130 | //Variable操作类 相关接口 | 150 | //Variable操作类 相关接口 |
| 131 | CcuResult CcuVariableAssignImm(CcuVariableHandle resVar, uint64_t immediate) | 151 | CcuResult CcuVariableAssignImm(CcuVariableHandle resVar, uint64_t immediate) |
| 132 | { | 152 | { |
| @@ -13,6 +13,7 @@ set(src_list | |||
| 13 | ccu_instance.cc | 13 | ccu_instance.cc |
| 14 | ccu_res_desc_mgr.cc | 14 | ccu_res_desc_mgr.cc |
| 15 | ccu_instance_mgr.cc | 15 | ccu_instance_mgr.cc |
| 16 | + ccu_var_event_res_mgr.cc | ||
| 16 | ) | 17 | ) |
| 17 | 18 | ||
| 18 | if(TARGET hcomm) | 19 | if(TARGET hcomm) |
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | #include "ccu_res_pack.h" | 20 | #include "ccu_res_pack.h" |
| 21 | #include "ccu_kernel_mgr.h" | 21 | #include "ccu_kernel_mgr.h" |
| 22 | +#include "ccu_var_event_res_mgr.h" | ||
| 22 | #include "ccu_res_specs.h" | 23 | #include "ccu_res_specs.h" |
| 23 | #include "ccu_dev_mgr_imp.h" | 24 | #include "ccu_dev_mgr_imp.h" |
| 24 | 25 | ||
| @@ -35,6 +36,8 @@ CcuInstance::~CcuInstance() | |||
| 35 | } | 36 | } |
| 36 | kernelHandles_.clear(); | 37 | kernelHandles_.clear(); |
| 37 | 38 | ||
| 39 | + (void)CcuVarEventResMgr::GetInstance(devLogicId_).ReleaseByInstance(insHandle_); | ||
| 40 | + | ||
| 38 | resPack_ = nullptr; // 释放instance持有的CCU资源 | 41 | resPack_ = nullptr; // 释放instance持有的CCU资源 |
| 39 | if (ccuDrvHandle_) { | 42 | if (ccuDrvHandle_) { |
| 40 | ccuDrvHandle_ = nullptr; // 先减少引用计数,再尝试关闭 | 43 | ccuDrvHandle_ = nullptr; // 先减少引用计数,再尝试关闭 |
| @@ -152,6 +155,8 @@ CcuResult CcuInstance::Reset() | |||
| 152 | 155 | ||
| 153 | untranslatedKernelHandles_.clear(); | 156 | untranslatedKernelHandles_.clear(); |
| 154 | CCU_CHK_RET(resPack_->Reset()); | 157 | CCU_CHK_RET(resPack_->Reset()); |
| 158 | + | ||
| 159 | + CCU_CHK_RET(CcuVarEventResMgr::GetInstance(devLogicId_).ExcludeAllocatedFromRepo(insHandle_)); | ||
| 155 | return CcuResult::CCU_SUCCESS; | 160 | return CcuResult::CCU_SUCCESS; |
| 156 | } | 161 | } |
| 157 | 162 | ||
| @@ -160,6 +165,11 @@ CcuResPack *CcuInstance::GetResPack() | |||
| 160 | return resPack_.get(); | 165 | return resPack_.get(); |
| 161 | } | 166 | } |
| 162 | 167 | ||
| 168 | +void CcuInstance::SetHandle(CcuInsHandle insHandle) | ||
| 169 | +{ | ||
| 170 | + insHandle_ = insHandle; | ||
| 171 | +} | ||
| 172 | + | ||
| 163 | // 累加某 die 上某资源 vector 中各 ResInfo::num,得到该 die 该资源的占用数量 | 173 | // 累加某 die 上某资源 vector 中各 ResInfo::num,得到该 die 该资源的占用数量 |
| 164 | static uint32_t SumResNum(const std::vector<ResInfo> &resInfos, std::string resName) | 174 | static uint32_t SumResNum(const std::vector<ResInfo> &resInfos, std::string resName) |
| 165 | { | 175 | { |
| @@ -42,6 +42,7 @@ public: | |||
| 42 | const CcuResDesc &GetTotalResDescs(uint8_t dieId) const; | 42 | const CcuResDesc &GetTotalResDescs(uint8_t dieId) const; |
| 43 | CcuResult SaveKernel(const CcuKernelHandle kernelHandle); | 43 | CcuResult SaveKernel(const CcuKernelHandle kernelHandle); |
| 44 | const std::vector<CcuKernelHandle> &GetUntranslatedKernels(); | 44 | const std::vector<CcuKernelHandle> &GetUntranslatedKernels(); |
| 45 | + void SetHandle(CcuInsHandle insHandle); | ||
| 45 | 46 | ||
| 46 | CcuResult BeginRegister(); | 47 | CcuResult BeginRegister(); |
| 47 | CcuResult CheckRegistering() const; | 48 | CcuResult CheckRegistering() const; |
| @@ -55,6 +56,7 @@ private: | |||
| 55 | enum class RegisterState { IDLE, REGISTERING, REGISTER_ABORTED }; | 56 | enum class RegisterState { IDLE, REGISTERING, REGISTER_ABORTED }; |
| 56 | RegisterState registerState_{RegisterState::IDLE}; | 57 | RegisterState registerState_{RegisterState::IDLE}; |
| 57 | int32_t devLogicId_{INT32_MAX}; | 58 | int32_t devLogicId_{INT32_MAX}; |
| 59 | + CcuInsHandle insHandle_{0}; | ||
| 58 | std::shared_ptr<hcomm::CcuDrvHandle> ccuDrvHandle_{}; | 60 | std::shared_ptr<hcomm::CcuDrvHandle> ccuDrvHandle_{}; |
| 59 | std::unique_ptr<CcuResPack> resPack_{}; | 61 | std::unique_ptr<CcuResPack> resPack_{}; |
| 60 | std::vector<CcuKernelHandle> kernelHandles_{}; | 62 | std::vector<CcuKernelHandle> kernelHandles_{}; |
| @@ -72,6 +72,7 @@ CcuResult CcuInstanceMgr::CreateByInsType(const CcuInstanceType insType, CcuInsH | |||
| 72 | CCU_CHK_RET(instance->InitByInsType(insType)); | 72 | CCU_CHK_RET(instance->InitByInsType(insType)); |
| 73 | 73 | ||
| 74 | instanceId_ += 1; | 74 | instanceId_ += 1; |
| 75 | + instance->SetHandle(instanceId_); | ||
| 75 | EXCEPTION_CATCH( | 76 | EXCEPTION_CATCH( |
| 76 | insMap_.emplace(instanceId_, std::move(instance)), | 77 | insMap_.emplace(instanceId_, std::move(instance)), |
| 77 | return CcuResult::CCU_E_INTERNAL); | 78 | return CcuResult::CCU_E_INTERNAL); |
| @@ -119,6 +120,7 @@ CcuResult CcuInstanceMgr::CreateByResDescs( | |||
| 119 | CCU_CHK_RET(instance->InitByResDescs(descs, descNum)); | 120 | CCU_CHK_RET(instance->InitByResDescs(descs, descNum)); |
| 120 | 121 | ||
| 121 | instanceId_ += 1; | 122 | instanceId_ += 1; |
| 123 | + instance->SetHandle(instanceId_); | ||
| 122 | EXCEPTION_CATCH( | 124 | EXCEPTION_CATCH( |
| 123 | insMap_.emplace(instanceId_, std::move(instance)), | 125 | insMap_.emplace(instanceId_, std::move(instance)), |
| 124 | return CcuResult::CCU_E_INTERNAL); | 126 | return CcuResult::CCU_E_INTERNAL); |
| @@ -138,6 +140,7 @@ CcuResult CcuInstanceMgr::CreateByAllRes(CcuInsHandle &insHandle) | |||
| 138 | CCU_CHK_RET(instance->InitByAllRes()); | 140 | CCU_CHK_RET(instance->InitByAllRes()); |
| 139 | 141 | ||
| 140 | instanceId_ += 1; | 142 | instanceId_ += 1; |
| 143 | + instance->SetHandle(instanceId_); | ||
| 141 | EXCEPTION_CATCH( | 144 | EXCEPTION_CATCH( |
| 142 | insMap_.emplace(instanceId_, std::move(instance)), | 145 | insMap_.emplace(instanceId_, std::move(instance)), |
| 143 | return CcuResult::CCU_E_INTERNAL); | 146 | return CcuResult::CCU_E_INTERNAL); |
| @@ -0,0 +1,576 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include "ccu_var_event_res_mgr.h" | ||
| 12 | + | ||
| 13 | +#include <mutex> | ||
| 14 | + | ||
| 15 | +#include "ccu_log.h" | ||
| 16 | +#include "hccl_common.h" | ||
| 17 | +#include "ccu_common.h" | ||
| 18 | + | ||
| 19 | +#include "ccu_dev_mgr_imp.h" | ||
| 20 | +#include "../ccu_device/ccu_res_specs.h" | ||
| 21 | + | ||
| 22 | +#include "rt_external.h" | ||
| 23 | + | ||
| 24 | +namespace hcomm { | ||
| 25 | + | ||
| 26 | +CcuVarEventResMgr &CcuVarEventResMgr::GetInstance(const int32_t deviceLogicId) | ||
| 27 | +{ | ||
| 28 | + static CcuVarEventResMgr resMgrs[MAX_MODULE_DEVICE_NUM + 1]; | ||
| 29 | + | ||
| 30 | + int32_t devLogicId = deviceLogicId; | ||
| 31 | + if (devLogicId < 0 || static_cast<uint32_t>(devLogicId) >= MAX_MODULE_DEVICE_NUM) { | ||
[LOW] GetInstance 边界检查逻辑可简化 问题分析:
建议修复: 简化为更直观的表达方式,或保持原样(这是代码风格问题,不影响功能)。
![]() ![]() | |||
| 32 | + HCCL_WARNING("[CcuVarEventResMgr][%s] use the backup device, devLogicId[%d] should be " | ||
| 33 | + "less than %u.", __func__, devLogicId, MAX_MODULE_DEVICE_NUM); | ||
| 34 | + devLogicId = MAX_MODULE_DEVICE_NUM; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + resMgrs[devLogicId].devLogicId_ = devLogicId; | ||
| 38 | + return resMgrs[devLogicId]; | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +CcuResult CcuVarEventResMgr::AllocFromPool(std::vector<ResInfo> &pool, uint32_t num, | ||
| 42 | + std::vector<ResInfo> &out) | ||
| 43 | +{ | ||
| 44 | + for (auto it = pool.begin(); it != pool.end(); ++it) { | ||
| 45 | + if (it->num < num) { | ||
| 46 | + continue; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + out.clear(); | ||
| 50 | + out.emplace_back(it->startId, num); | ||
| 51 | + | ||
| 52 | + if (it->num == num) { | ||
| 53 | + pool.erase(it); | ||
| 54 | + } else { | ||
| 55 | + it->startId += num; | ||
| 56 | + it->num -= num; | ||
| 57 | + } | ||
| 58 | + return CCU_SUCCESS; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + return CCU_E_UNAVAIL; | ||
| 62 | +} | ||
| 63 | + | ||
| 64 | +void CcuVarEventResMgr::ReturnToPool(std::vector<ResInfo> &pool, const std::vector<ResInfo> &res) | ||
| 65 | +{ | ||
| 66 | + for (const auto &info : res) { | ||
| 67 | + if (info.num == 0) { | ||
| 68 | + continue; | ||
| 69 | + } | ||
| 70 | + pool.emplace_back(info.startId, info.num); | ||
[LOW] ReturnToPool 不合并相邻空闲块 第 70 行: 问题分析:
建议修复: ReturnToPool 追加后对 pool 按 startId 排序并合并相邻块。若性能敏感,可惰性合并(仅当 AllocFromPool 找不到连续块时触发一次全量合并)。注意合并需在 mapMutex_ 保护下或 pool 所属 instance 的单线程上下文中执行。 ![]() ![]() [MEDIUM] ReturnToPool 简单追加可能导致长期碎片化 问题分析:
建议修复: 在 ReturnToPool 后调用一个合并函数(可选优化),对 pool 排序并合并相邻 block。 注意:这是一个性能优化,不是 correctness 问题。是否需要合并取决于实际碎片化情况。
![]() ![]() | |||
| 71 | + } | ||
| 72 | +} | ||
| 73 | + | ||
| 74 | +static std::vector<ResInfo> *SelectPool(CcuResRepository &resRepo, CcuVarEventType type, uint8_t dieId) | ||
| 75 | +{ | ||
| 76 | + switch (type) { | ||
| 77 | + case CcuVarEventType::VARIABLE: | ||
| 78 | + return &resRepo.blockXn[dieId]; | ||
| 79 | + case CcuVarEventType::EVENT: | ||
| 80 | + return &resRepo.blockCke[dieId]; | ||
| 81 | + default: | ||
| 82 | + return nullptr; | ||
| 83 | + } | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +// 由预约资源类型推导runtime资源类型,不支持的类型返回false | ||
| 87 | +static bool GetRtResType(CcuVarEventType type, rtDevResType_t &resType) | ||
| 88 | +{ | ||
| 89 | + switch (type) { | ||
| 90 | + case CcuVarEventType::VARIABLE: | ||
| 91 | + resType = RT_RES_TYPE_CCU_XN; | ||
| 92 | + return true; | ||
| 93 | + case CcuVarEventType::EVENT: | ||
| 94 | + resType = RT_RES_TYPE_CCU_CKE; | ||
| 95 | + return true; | ||
| 96 | + default: | ||
| 97 | + return false; | ||
| 98 | + } | ||
| 99 | +} | ||
| 100 | + | ||
| @@ -0,0 +1,110 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#ifndef HCOMM_CCU_VAR_EVENT_RES_MGR_H | ||
| 12 | +#define HCOMM_CCU_VAR_EVENT_RES_MGR_H | ||
| 13 | + | ||
| 14 | +#include <shared_mutex> | ||
| 15 | +#include <vector> | ||
| 16 | +#include <unordered_map> | ||
| 17 | + | ||
| 18 | +#include "ccu_types.h" | ||
| 19 | + | ||
| 20 | +#include "ccu_res_repo.h" | ||
| 21 | + | ||
| 22 | +namespace hcomm { | ||
| 23 | + | ||
| 24 | +enum class CcuVarEventType { | ||
| 25 | + VARIABLE = 0, | ||
| 26 | + EVENT = 1, | ||
| 27 | +}; | ||
| 28 | + | ||
| 29 | +struct CcuVarEventRes { | ||
| 30 | + CcuInsHandle insHandle{0}; | ||
| 31 | + int32_t devLogicId{-1}; | ||
[LOW] CcuVarEventRes::devLogicId 为死字段 第 31 行: 问题分析:
建议修复: 若确无使用计划,删除 CcuVarEventRes::devLogicId 字段及其赋值。若保留用于调试,加注释说明用途并在至少一条日志中引用。 ![]() ![]() | |||
| 32 | + uint8_t dieId{0}; | ||
| 33 | + CcuVarEventType type{CcuVarEventType::VARIABLE}; | ||
| 34 | + std::vector<ResInfo> resInfos{}; | ||
| 35 | + // 借用指针,指向发起预约的 CcuInstance 名下 CcuResPack 持有的资源仓,本类不持有所有权。 | ||
| 36 | + // 有效性依赖既定时序:~CcuInstance 中 ReleaseByInstance 先于 resPack_ 置空执行, | ||
| 37 | + // CcuInstance::Reset 调 ExcludeAllocatedFromRepo 时资源仓亦仍存活。 | ||
| 38 | + // 新增读写该指针的路径时,须确认调用点仍在 CcuResPack 析构之前。 | ||
| 39 | + CcuResRepository *resRepo{nullptr}; | ||
| 40 | + // 申请时对每个资源注册好的进程可访问 VA,下标与资源 index 一一对应 | ||
| 41 | + std::vector<uint64_t> vaList{}; | ||
| 42 | +}; | ||
| 43 | + | ||
| 44 | +// 职责:管理通信域内 Variable(XN) / Event(CKE) 预约资源的完整生命周期,涵盖四个阶段—— | ||
| 45 | +// 从实例资源仓切出连续块、申请期为每个资源注册进程可访问 VA、按 handle 记账、随实例回收。 | ||
| 46 | +// 四者是同一份资源的先后阶段而非彼此独立的职责,故收敛在同一个类内:Acquire 完成 | ||
| 47 | +// 「切块 + 映射 + 记账」,ReleaseByHandle / ReleaseByInstance 完成对称的「解映射 + 归还」。 | ||
| 48 | +// | ||
| 49 | +// 为何 Variable 与 Event 合用一个管理器:两类资源共享完全相同的使用模式——一次性预约连续块、 | ||
| 50 | +// 申请期暴露地址、句柄随通信域销毁统一回收;差异仅在资源池(blockXn / blockCke)与 runtime | ||
| 51 | +// 资源类型(RT_RES_TYPE_CCU_XN / RT_RES_TYPE_CCU_CKE)两处,均由 CcuVarEventType 参数化。 | ||
| 52 | +// 拆成两个类会使上述四阶段流程与回滚逻辑重复一遍,故不拆。 | ||
| 53 | +// | ||
| 54 | +// 与 CcuResIdAllocator 的边界:后者位于设备层,管理自持的 [0, capacity) 完整 id 空间, | ||
| 55 | +// 其 resInfos_ 记录的是「已分配块」;本类位于实例层,从上游下发给本通信域的若干段「空闲块」 | ||
| 56 | +// 中做二次切分,无 capacity 概念。两者数据结构语义相反,不存在替代关系。 | ||
| 57 | +// | ||
| 58 | +// 线程安全契约: | ||
| 59 | +// 1) resMap_ 与 handleSeed_ 为 per-device、跨 CcuInstance 共享,全部读写均由 mapMutex_ 保护; | ||
| 60 | +// 2) CcuVarEventRes::resRepo 指向的资源池由发起预约的 CcuInstance(经其 CcuResPack)持有, | ||
| 61 | +// 不在 mapMutex_ 的保护范围内。CcuInstance 自身不含锁,约定同一 instance 只由单线程串行 | ||
| 62 | +// 访问,池的并发安全由该约定保证;不同 instance 的池互不相交,跨 instance 并发是安全的。 | ||
| 63 | +// 因此 ExcludeAllocatedFromRepo 取 shared_lock 是为遍历 resMap_,而非保护池。 | ||
| 64 | +class CcuVarEventResMgr { | ||
| 65 | +public: | ||
| 66 | + static CcuVarEventResMgr &GetInstance(const int32_t deviceLogicId); | ||
| 67 | + | ||
| 68 | + // 预约一段连续资源并在申请期完成地址映射;任一阶段失败均整笔回滚,仅全程成功才写 handle | ||
| 69 | + CcuResult Acquire(CcuInsHandle insHandle, CcuResRepository &resRepo, CcuVarEventType type, | ||
| 70 | + uint8_t dieId, uint32_t num, uint64_t &handle); | ||
| 71 | + CcuResult GetVariableXnId(uint64_t handle, uint32_t index, uint8_t &dieId, uint32_t &xnId) const; | ||
| 72 | + CcuResult GetEventCkeId(uint64_t handle, uint32_t index, uint8_t &dieId, uint32_t &ckeId) const; | ||
| 73 | + // 保存 Alloc 阶段为该 handle 注册好的全部资源 VA(下标与资源 index 一一对应) | ||
| 74 | + CcuResult SaveAddrs(CcuVarEventType type, uint64_t handle, const std::vector<uint64_t> &vaList); | ||
| 75 | + // 返回 Alloc 阶段已注册的第 index 个资源 VA | ||
| 76 | + CcuResult GetSavedAddr(CcuVarEventType type, uint64_t handle, uint32_t index, uint64_t &va) const; | ||
| 77 | + CcuResult ReleaseByHandle(uint64_t handle); | ||
| 78 | + CcuResult ReleaseByInstance(CcuInsHandle insHandle); | ||
| 79 | + CcuResult ExcludeAllocatedFromRepo(CcuInsHandle insHandle) const; | ||
| 80 | + | ||
| 81 | +private: | ||
| 82 | + explicit CcuVarEventResMgr() = default; | ||
| 83 | + ~CcuVarEventResMgr() = default; | ||
| 84 | + | ||
| 85 | + CcuVarEventResMgr(const CcuVarEventResMgr &that) = delete; | ||
| 86 | + CcuVarEventResMgr &operator=(const CcuVarEventResMgr &that) = delete; | ||
| 87 | + | ||
| 88 | + // 校验参数、选池、切出连续块并登记到 resMap_,成功时经 newHandle 返回新句柄 | ||
| 89 | + CcuResult AllocAndRecord(CcuInsHandle insHandle, CcuResRepository &resRepo, | ||
| 90 | + CcuVarEventType type, uint8_t dieId, uint32_t num, uint64_t &newHandle); | ||
| 91 | + // 为 handle 名下 num 个资源逐个注册进程可访问 VA 并缓存;失败时解除本次已完成的映射, | ||
| 92 | + // 资源池的归还由 Acquire 与切池动作配对完成 | ||
| 93 | + CcuResult RegisterAddrs(CcuVarEventType type, uint64_t handle, uint32_t num); | ||
| 94 | + | ||
| 95 | + static CcuResult AllocFromPool(std::vector<ResInfo> &pool, uint32_t num, | ||
| 96 | + std::vector<ResInfo> &out); | ||
| 97 | + static void ReturnToPool(std::vector<ResInfo> &pool, const std::vector<ResInfo> &res); | ||
| 98 | + // 释放资源前,将 Alloc 阶段映射的进程可访问 VA 逐个 unmap(仅处理已保存 VA 的资源); | ||
| 99 | + // 返回首个 unmap 失败的错误码,失败不中断,其余资源继续 unmap | ||
| 100 | + static CcuResult UnmapSavedAddrs(const CcuVarEventRes &res); | ||
| 101 | + | ||
| 102 | + int32_t devLogicId_{-1}; | ||
| 103 | + uint64_t handleSeed_{0}; | ||
| 104 | + mutable std::shared_timed_mutex mapMutex_; | ||
| 105 | + std::unordered_map<uint64_t, CcuVarEventRes> resMap_{}; | ||
| 106 | +}; | ||
| 107 | + | ||
| 108 | +} // namespace hcomm | ||
| 109 | + | ||
| 110 | +#endif // HCOMM_CCU_VAR_EVENT_RES_MGR_H | ||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include "ccu_rep_context_v1.h" | 25 | #include "ccu_rep_context_v1.h" |
| 26 | #include "ccu_rep_funccall_v1.h" | 26 | #include "ccu_rep_funccall_v1.h" |
| 27 | #include "../../endpoint_pairs/channels/ccu/ccu_urma_channel.h" | 27 | #include "../../endpoint_pairs/channels/ccu/ccu_urma_channel.h" |
| 28 | +#include "../ccu_instance/ccu_var_event_res_mgr.h" | ||
| 28 | 29 | ||
| 29 | #include "ccu_log.h" | 30 | #include "ccu_log.h" |
| 30 | 31 | ||
| @@ -535,6 +536,38 @@ CcuResult CcuKernel::VariableCreateByChannel(ChannelHandle channel, uint32_t var | |||
| 535 | return CcuResult::CCU_SUCCESS; | 536 | return CcuResult::CCU_SUCCESS; |
| 536 | } | 537 | } |
| 537 | 538 | ||
| 539 | +CcuResult CcuKernel::VariableCreateByAcquire(CcuVariableHandle acqHandle, uint32_t index, | ||
| 540 | + CcuVariableHandle *varHandle) | ||
| 541 | +{ | ||
| 542 | + uint8_t dieId = 0; | ||
| 543 | + uint32_t xnId = 0; | ||
| 544 | + CCU_CHK_RET(CcuVarEventResMgr::GetInstance(HcclGetThreadDeviceId()) | ||
| 545 | + .GetVariableXnId(acqHandle, index, dieId, xnId)); | ||
| 546 | + | ||
| 547 | + CcuRep::Variable var(this); | ||
| 548 | + var.Reset(static_cast<uint16_t>(xnId), static_cast<uint16_t>(dieId)); | ||
[MEDIUM] VariableCreateByAcquire 将 uint32_t xnId 截断为 uint16_t 第 548 行: 问题分析:
建议修复: 在截断前加范围校验,超限返回错误码而非静默截断:
或在 CcuVarEventResMgr::AllocFromPool 阶段确保资源 ID 不超 uint16_t 范围。 ![]() ![]() | |||
| 549 | + CcuVariableHandle handle = ccuVarMap_.size(); | ||
| 550 | + ccuVarMap_.emplace(handle, var); | ||
| 551 | + *varHandle = handle; | ||
| 552 | + return CcuResult::CCU_SUCCESS; | ||
| 553 | +} | ||
| 554 | + | ||
| 555 | +CcuResult CcuKernel::EventCreateByAcquire(CcuEventHandle acqHandle, uint32_t index, | ||
| 556 | + CcuEventHandle *eventHandle) | ||
| 557 | +{ | ||
| 558 | + uint8_t dieId = 0; | ||
| 559 | + uint32_t ckeId = 0; | ||
| 560 | + CCU_CHK_RET(CcuVarEventResMgr::GetInstance(HcclGetThreadDeviceId()) | ||
| 561 | + .GetEventCkeId(acqHandle, index, dieId, ckeId)); | ||
| 562 | + | ||
| 563 | + CcuRep::CompletedEvent event(this); | ||
| 564 | + event.Reset(static_cast<uint16_t>(ckeId), static_cast<uint16_t>(dieId)); | ||
[MEDIUM] EventCreateByAcquire 将 uint32_t ckeId 截断为 uint16_t 第 564 行: 问题分析:
建议修复:
![]() ![]() | |||
| 565 | + CcuEventHandle handle = ccuEventMap_.size(); | ||
| 566 | + ccuEventMap_.emplace(handle, event); | ||
| 567 | + *eventHandle = handle; | ||
| 568 | + return CcuResult::CCU_SUCCESS; | ||
| 569 | +} | ||
| 570 | + | ||
| 538 | CcuResult CcuKernel::VariableAssignImm(CcuVariableHandle varHandle, uint64_t immediate) | 571 | CcuResult CcuKernel::VariableAssignImm(CcuVariableHandle varHandle, uint64_t immediate) |
| 539 | { | 572 | { |
| 540 | PLF_CONFIG_INFO(PLF_DATA_OP, "[VariableAssignImm] varHandle=%llu, immediate=%llu", varHandle, immediate); | 573 | PLF_CONFIG_INFO(PLF_DATA_OP, "[VariableAssignImm] varHandle=%llu, immediate=%llu", varHandle, immediate); |
| @@ -125,6 +125,8 @@ public: | |||
| 125 | CcuResult BlockEventAlloc(CcuEventHandle *eventHandles, uint32_t count); | 125 | CcuResult BlockEventAlloc(CcuEventHandle *eventHandles, uint32_t count); |
| 126 | CcuResult BlockBufferAlloc(CcuBufferHandle *bufHandles, uint32_t count); | 126 | CcuResult BlockBufferAlloc(CcuBufferHandle *bufHandles, uint32_t count); |
| 127 | CcuResult VariableCreateByChannel(ChannelHandle channel, uint32_t varIndex, CcuVariableHandle *varHandle); | 127 | CcuResult VariableCreateByChannel(ChannelHandle channel, uint32_t varIndex, CcuVariableHandle *varHandle); |
| 128 | + CcuResult VariableCreateByAcquire(CcuVariableHandle acqHandle, uint32_t index, CcuVariableHandle *varHandle); | ||
| 129 | + CcuResult EventCreateByAcquire(CcuEventHandle acqHandle, uint32_t index, CcuEventHandle *eventHandle); | ||
| 128 | 130 | ||
| 129 | //参数加载类 相关接口 | 131 | //参数加载类 相关接口 |
| 130 | CcuResult LoadArg(CcuVariableHandle varHandle, uint32_t argId); | 132 | CcuResult LoadArg(CcuVariableHandle varHandle, uint32_t argId); |
| @@ -0,0 +1,41 @@ | |||
| 1 | +/** | ||
| 2 | + * Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | + * This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | + * CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | + * Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | + * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | + * See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +#include "ccu_primitives.hpp" | ||
| 12 | +#include "ccu_types.h" | ||
| 13 | + | ||
| 14 | +namespace ccu = ::AscendC::ccu; | ||
| 15 | + | ||
| 16 | +struct CcuVarAcquireDemoKernelArg { | ||
| 17 | + CcuVariableHandle acqHandle{0}; | ||
| 18 | + uint32_t varNum{0}; | ||
| 19 | + CcuEventHandle acqEventHandle{0}; | ||
| 20 | + uint32_t eventNum{0}; | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +CcuResult CcuVarAcquireDemoKernel(CcuKernelArg arg) | ||
| 24 | +{ | ||
| 25 | + auto *args = static_cast<CcuVarAcquireDemoKernelArg *>(arg); | ||
| 26 | + | ||
| 27 | + ccu::Variable sum; | ||
| 28 | + sum = 0; | ||
| 29 | + ccu::Array<ccu::Variable> vars(args->acqHandle, args->varNum); | ||
| 30 | + for (uint32_t i = 0; i < vars.size(); i++) { | ||
| 31 | + vars[i] = i; | ||
| 32 | + sum += vars[i]; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + ccu::Array<ccu::Event> events(args->acqEventHandle, args->eventNum); | ||
| 36 | + for (uint32_t i = 0; i < events.size(); i++) { | ||
| 37 | + ccu::EventRecord(events[i]); | ||
| 38 | + ccu::EventWait(events[i]); | ||
| 39 | + } | ||
| 40 | + return CcuResult::CCU_SUCCESS; | ||
| 41 | +} | ||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "ccu_pfe_cfg_mgr.h" | 31 | #include "ccu_pfe_cfg_mgr.h" |
| 32 | #include "ccu_launch.h" | 32 | #include "ccu_launch.h" |
| 33 | #include "ccu_res.h" | 33 | #include "ccu_res.h" |
| 34 | +#include "ccu_var_event_res_mgr.h" | ||
| 34 | 35 | ||
| 35 | #include "mocks/ccu_device_mock_utils.h" | 36 | #include "mocks/ccu_device_mock_utils.h" |
| 36 | #include "mocks/ccu_channel_mock_utils.h" | 37 | #include "mocks/ccu_channel_mock_utils.h" |
| @@ -47,6 +48,7 @@ | |||
| 47 | #include "ccu_kernel_impl/ccu_reduce_scatter_mesh1d_demo.h" | 48 | #include "ccu_kernel_impl/ccu_reduce_scatter_mesh1d_demo.h" |
| 48 | #include "ccu_kernel_impl/ccu_reduce_scatter_mesh1d_a6_demo.h" | 49 | #include "ccu_kernel_impl/ccu_reduce_scatter_mesh1d_a6_demo.h" |
| 49 | #include "ccu_kernel_impl/ccu_groupcopy_demo.h" | 50 | #include "ccu_kernel_impl/ccu_groupcopy_demo.h" |
| 51 | +#include "ccu_kernel_impl/ccu_var_acquire_demo.h" | ||
| 50 | 52 | ||
| 51 | #undef protected | 53 | #undef protected |
| 52 | #undef private | 54 | #undef private |
| @@ -1374,6 +1376,107 @@ TEST_F(HcommCcuControlApiTest, Ut_HcommCcuKernelReduceScatterMesh1d_When_V2_Expe | |||
| 1374 | DestroyCcuResDescs(resDescs); | 1376 | DestroyCcuResDescs(resDescs); |
| 1375 | } | 1377 | } |
| 1376 | 1378 | ||
| 1379 | +TEST_F(HcommCcuControlApiTest, Ut_HcommCcuVariableAllocConsecutive_When_AllFine_Expect_ReturnCcuSUCCESS) | ||
| 1380 | +{ | ||
| 1381 | + CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | ||
| 1382 | + constexpr uint32_t fakeDevId = MAX_MODULE_DEVICE_NUM - 13; | ||
| 1383 | + constexpr hcomm::CcuVersion fakeCcuVersion = hcomm::CcuVersion::CCU_V1; | ||
| 1384 | + const int32_t fakeDeviceLogicId = MockCcuDeviceEnv(fakeDevId, fakeCcuVersion); | ||
| 1385 | + | ||
| 1386 | + constexpr auto MS_INS_TPYE = CcuInstanceType::CCU_MS; | ||
| 1387 | + CcuInsHandle insHandle{0}; | ||
| 1388 | + ccuRet = HcommCcuInsCreateLegacy(MS_INS_TPYE, &insHandle); | ||
| 1389 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1390 | + | ||
| 1391 | + constexpr uint8_t fakeDieId = 0; | ||
| 1392 | + constexpr uint32_t varNum = 10; | ||
| 1393 | + CcuVariableHandle varHandle{0}; | ||
| 1394 | + ccuRet = HcommCcuVariableAlloc(insHandle, fakeDieId, varNum, &varHandle); | ||
| 1395 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1396 | + | ||
| 1397 | + for(int i=0; i<varNum; i++) { | ||
| 1398 | + uint64_t startVa = 0; | ||
| 1399 | + ccuRet = HcommCcuVariableGetAddr(varHandle, i, &startVa); | ||
| 1400 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1401 | + std::cout << "[Ut_HcommCcuVariableAllocConsecutive] varHandle=0x" << std::hex << varHandle | ||
| 1402 | + << ", startVa=0x" << startVa << std::dec << ", i=" << i << std::endl; | ||
| 1403 | + } | ||
| 1404 | + | ||
| 1405 | + auto &resMgr = hcomm::CcuVarEventResMgr::GetInstance(fakeDeviceLogicId); | ||
| 1406 | + auto it = resMgr.resMap_.find(varHandle); | ||
| 1407 | + ASSERT_NE(it, resMgr.resMap_.end()); | ||
| 1408 | + const auto &resInfos = it->second.resInfos; | ||
| 1409 | + EXPECT_EQ(resInfos.size(), 1U); | ||
| 1410 | + | ||
| 1411 | + uint32_t totalNum = 0; | ||
| 1412 | + for (const auto &info : resInfos) { | ||
| 1413 | + std::cout << " consecutive block: startId=" << info.startId << ", num=" << info.num | ||
| 1414 | + << ", xn ids=["; | ||
| 1415 | + for (uint32_t i = 0; i < info.num; i++) { | ||
| 1416 | + std::cout << (info.startId + i); | ||
| 1417 | + if (i + 1 < info.num) { | ||
| 1418 | + std::cout << ", "; | ||
| 1419 | + } | ||
| 1420 | + } | ||
| 1421 | + std::cout << "]" << std::endl; | ||
| 1422 | + totalNum += info.num; | ||
| 1423 | + } | ||
| 1424 | + EXPECT_EQ(totalNum, varNum); | ||
| 1425 | + | ||
| 1426 | + CcuEventHandle eventHandle{0}; | ||
| 1427 | + constexpr uint32_t eventNum = 4; | ||
| 1428 | + ccuRet = HcommCcuEventAlloc(insHandle, fakeDieId, eventNum, &eventHandle); | ||
| 1429 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1430 | + | ||
| 1431 | + for(int i=0; i<eventNum; i++) { | ||
| 1432 | + uint64_t eventVa = 0; | ||
| 1433 | + ccuRet = HcommCcuEventGetAddr(eventHandle, i, &eventVa); | ||
| 1434 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1435 | + std::cout << "[Ut_HcommCcuVariableAllocConsecutive] eventHandle=0x" << std::hex << eventHandle | ||
| 1436 | + << ", eventVa=0x" << eventVa << std::dec << ", i=" << i << std::endl; | ||
| 1437 | + } | ||
| 1438 | + | ||
| 1439 | + auto eventIt = resMgr.resMap_.find(eventHandle); | ||
| 1440 | + ASSERT_NE(eventIt, resMgr.resMap_.end()); | ||
| 1441 | + const auto &ckeInfos = eventIt->second.resInfos; | ||
| 1442 | + EXPECT_EQ(ckeInfos.size(), 1U); | ||
| 1443 | + for (const auto &info : ckeInfos) { | ||
| 1444 | + std::cout << " consecutive block: startId=" << info.startId << ", num=" << info.num | ||
| 1445 | + << ", xn ids=["; | ||
| 1446 | + for (uint32_t i = 0; i < info.num; i++) { | ||
| 1447 | + std::cout << (info.startId + i); | ||
| 1448 | + if (i + 1 < info.num) { | ||
| 1449 | + std::cout << ", "; | ||
| 1450 | + } | ||
| 1451 | + } | ||
| 1452 | + std::cout << "]" << std::endl; | ||
| 1453 | + } | ||
| 1454 | + | ||
| 1455 | + ccuRet = HcommCcuKernelRegisterStart(insHandle); | ||
| 1456 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1457 | + | ||
| 1458 | + CcuVarAcquireDemoKernelArg demoArg{}; | ||
| 1459 | + demoArg.acqHandle = varHandle; | ||
| 1460 | + demoArg.varNum = varNum; | ||
| 1461 | + demoArg.acqEventHandle = eventHandle; | ||
| 1462 | + demoArg.eventNum = eventNum; | ||
| 1463 | + auto kernelFunc = reinterpret_cast<void *>(CcuVarAcquireDemoKernel); | ||
| 1464 | + auto kernelArg = static_cast<CcuKernelArg>(&demoArg); | ||
| 1465 | + const void *kernelArgs[] = {kernelArg}; | ||
| 1466 | + char *kernelFuncName = "ccu_var_acquire_demo"; | ||
| 1467 | + CcuKernelHandle kernelHandle{0}; | ||
| 1468 | + constexpr uint32_t kernelArgNum = 1; | ||
| 1469 | + ccuRet = HcommCcuKernelRegister(insHandle, fakeDieId, | ||
| 1470 | + kernelFuncName, kernelFunc, kernelArgs, kernelArgNum, &kernelHandle); | ||
| 1471 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1472 | + | ||
| 1473 | + ccuRet = HcommCcuKernelRegisterEnd(insHandle); | ||
| 1474 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1475 | + | ||
| 1476 | + ccuRet = HcommCcuInsDestroy(insHandle); | ||
| 1477 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1478 | +} | ||
| 1479 | + | ||
| 1377 | TEST_F(HcommCcuControlApiTest, Ut_HcommCcuKernelNestedInIfIf_When_AllFine_Expect_ReturnCcuSUCCESS) | 1480 | TEST_F(HcommCcuControlApiTest, Ut_HcommCcuKernelNestedInIfIf_When_AllFine_Expect_ReturnCcuSUCCESS) |
| 1378 | { | 1481 | { |
| 1379 | CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | 1482 | CcuResult ccuRet = CcuResult::CCU_E_RESERVED; |
| @@ -1427,6 +1530,247 @@ TEST_F(HcommCcuControlApiTest, Ut_HcommCcuKernelNestedInIfIf_When_AllFine_Expect | |||
| 1427 | DestroyCcuResDescs(resDescs); | 1530 | DestroyCcuResDescs(resDescs); |
| 1428 | } | 1531 | } |
| 1429 | 1532 | ||
| 1533 | +TEST_F(HcommCcuControlApiTest, Ut_HcommCcuVariableAndEventAllocAddrGet_When_AllFine_Expect_ReturnCcuSUCCESS) | ||
| 1534 | +{ | ||
| 1535 | + CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | ||
| 1536 | + constexpr uint32_t fakeDevId = MAX_MODULE_DEVICE_NUM - 14; | ||
| 1537 | + constexpr hcomm::CcuVersion fakeCcuVersion = hcomm::CcuVersion::CCU_V1; | ||
| 1538 | + const int32_t fakeDeviceLogicId = MockCcuDeviceEnv(fakeDevId, fakeCcuVersion); | ||
| 1539 | + | ||
| 1540 | + // ccuInstance构建(正常在通信域创建中,本用例仅测试hcomm接口) | ||
| 1541 | + constexpr auto MS_INS_TPYE = CcuInstanceType::CCU_MS; | ||
| 1542 | + CcuInsHandle insHandle{0}; | ||
| 1543 | + ccuRet = HcommCcuInsCreateLegacy(MS_INS_TPYE, &insHandle); | ||
| 1544 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1545 | + | ||
| 1546 | + constexpr uint8_t fakeDieId = 0; | ||
| 1547 | + | ||
| 1548 | + constexpr uint32_t varNum = 8; | ||
| 1549 | + CcuVariableHandle varHandle{0}; | ||
| 1550 | + ccuRet = HcommCcuVariableAlloc(insHandle, fakeDieId, varNum, &varHandle); | ||
| 1551 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1552 | + | ||
| 1553 | + for (uint32_t i = 0; i < varNum; i++) { | ||
| 1554 | + uint64_t startVa = 0; | ||
| 1555 | + ccuRet = HcommCcuVariableGetAddr(varHandle, i, &startVa); | ||
| 1556 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1557 | + EXPECT_NE(startVa, 0U); | ||
| 1558 | + } | ||
| 1559 | + | ||
| 1560 | + // 越界index应返回失败 | ||
| 1561 | + uint64_t invalidVa = 0; | ||
| 1562 | + ccuRet = HcommCcuVariableGetAddr(varHandle, varNum, &invalidVa); | ||
| 1563 | + EXPECT_NE(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1564 | + | ||
| 1565 | + constexpr uint32_t eventNum = 4; | ||
| 1566 | + CcuEventHandle eventHandle{0}; | ||
| 1567 | + ccuRet = HcommCcuEventAlloc(insHandle, fakeDieId, eventNum, &eventHandle); | ||
| 1568 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1569 | + | ||
| 1570 | + for (uint32_t i = 0; i < eventNum; i++) { | ||
| 1571 | + uint64_t eventVa = 0; | ||
| 1572 | + ccuRet = HcommCcuEventGetAddr(eventHandle, i, &eventVa); | ||
| 1573 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1574 | + EXPECT_NE(eventVa, 0U); | ||
| 1575 | + } | ||
| 1576 | + | ||
| 1577 | + // 越界index应返回失败 | ||
| 1578 | + uint64_t invalidEventVa = 0; | ||
| 1579 | + ccuRet = HcommCcuEventGetAddr(eventHandle, eventNum, &invalidEventVa); | ||
| 1580 | + EXPECT_NE(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1581 | + | ||
| 1582 | + // 校验资源管理器中记录了对应连续资源块 | ||
| 1583 | + auto &resMgr = hcomm::CcuVarEventResMgr::GetInstance(fakeDeviceLogicId); | ||
| 1584 | + auto varIt = resMgr.resMap_.find(varHandle); | ||
| 1585 | + ASSERT_NE(varIt, resMgr.resMap_.end()); | ||
| 1586 | + uint32_t varTotal = 0; | ||
| 1587 | + for (const auto &info : varIt->second.resInfos) { | ||
| 1588 | + varTotal += info.num; | ||
| 1589 | + } | ||
| 1590 | + EXPECT_EQ(varTotal, varNum); | ||
| 1591 | + | ||
| 1592 | + auto eventIt = resMgr.resMap_.find(eventHandle); | ||
| 1593 | + ASSERT_NE(eventIt, resMgr.resMap_.end()); | ||
| 1594 | + uint32_t eventTotal = 0; | ||
| 1595 | + for (const auto &info : eventIt->second.resInfos) { | ||
| 1596 | + eventTotal += info.num; | ||
| 1597 | + } | ||
| 1598 | + EXPECT_EQ(eventTotal, eventNum); | ||
| 1599 | + | ||
| 1600 | + ccuRet = HcommCcuInsDestroy(insHandle); | ||
| 1601 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1602 | +} | ||
| 1603 | + | ||
| 1604 | +TEST_F(HcommCcuControlApiTest, Ut_HcommCcuVarEventAlloc_When_InvalidParam_Expect_ReturnFailed) | ||
| 1605 | +{ | ||
| 1606 | + CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | ||
| 1607 | + constexpr uint32_t fakeDevId = MAX_MODULE_DEVICE_NUM - 15; | ||
| 1608 | + constexpr hcomm::CcuVersion fakeCcuVersion = hcomm::CcuVersion::CCU_V1; | ||
| 1609 | + const int32_t fakeDeviceLogicId = MockCcuDeviceEnv(fakeDevId, fakeCcuVersion); | ||
| 1610 | + | ||
| 1611 | + constexpr auto MS_INS_TPYE = CcuInstanceType::CCU_MS; | ||
| 1612 | + CcuInsHandle insHandle{0}; | ||
| 1613 | + ccuRet = HcommCcuInsCreateLegacy(MS_INS_TPYE, &insHandle); | ||
| 1614 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1615 | + | ||
| 1616 | + constexpr uint8_t fakeDieId = 0; | ||
| 1617 | + constexpr uint32_t validNum = 4; | ||
| 1618 | + CcuVariableHandle varHandle{0xFFFF}; | ||
| 1619 | + CcuEventHandle eventHandle{0xFFFF}; | ||
| 1620 | + | ||
| 1621 | + // num 为 0:参数非法,且出参必须被清 0,避免调用方误用脏值 | ||
| 1622 | + ccuRet = HcommCcuVariableAlloc(insHandle, fakeDieId, 0, &varHandle); | ||
| 1623 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_PARA); | ||
| 1624 | + EXPECT_EQ(varHandle, 0U); | ||
| 1625 | + varHandle = 0xFFFF; | ||
| 1626 | + ccuRet = HcommCcuEventAlloc(insHandle, fakeDieId, 0, &eventHandle); | ||
| 1627 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_PARA); | ||
| 1628 | + EXPECT_EQ(eventHandle, 0U); | ||
| 1629 | + eventHandle = 0xFFFF; | ||
| 1630 | + | ||
| 1631 | + // dieId 越界:参数非法 | ||
| 1632 | + constexpr uint8_t invalidDieId = static_cast<uint8_t>(hcomm::CCU_MAX_IODIE_NUM); | ||
| 1633 | + ccuRet = HcommCcuVariableAlloc(insHandle, invalidDieId, validNum, &varHandle); | ||
| 1634 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_PARA); | ||
| 1635 | + EXPECT_EQ(varHandle, 0U); | ||
| 1636 | + varHandle = 0xFFFF; | ||
| 1637 | + ccuRet = HcommCcuEventAlloc(insHandle, invalidDieId, validNum, &eventHandle); | ||
| 1638 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_PARA); | ||
| 1639 | + EXPECT_EQ(eventHandle, 0U); | ||
| 1640 | + | ||
| 1641 | + // 出参指针为空 | ||
| 1642 | + EXPECT_EQ(HcommCcuVariableAlloc(insHandle, fakeDieId, validNum, nullptr), CcuResult::CCU_E_PTR); | ||
| 1643 | + EXPECT_EQ(HcommCcuEventAlloc(insHandle, fakeDieId, validNum, nullptr), CcuResult::CCU_E_PTR); | ||
| 1644 | + | ||
| 1645 | + // 池中无长度足够的连续块:资源不可用 | ||
| 1646 | + constexpr uint32_t hugeNum = 100000; | ||
| 1647 | + varHandle = 0xFFFF; | ||
| 1648 | + ccuRet = HcommCcuVariableAlloc(insHandle, fakeDieId, hugeNum, &varHandle); | ||
| 1649 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_UNAVAIL); | ||
| 1650 | + EXPECT_EQ(varHandle, 0U); | ||
| 1651 | + eventHandle = 0xFFFF; | ||
| 1652 | + ccuRet = HcommCcuEventAlloc(insHandle, fakeDieId, hugeNum, &eventHandle); | ||
| 1653 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_UNAVAIL); | ||
| 1654 | + EXPECT_EQ(eventHandle, 0U); | ||
| 1655 | + | ||
| 1656 | + // AddrGet 的错误路径:句柄不存在 / 句柄类型不符 / 出参指针为空 | ||
| 1657 | + uint64_t va = 0; | ||
| 1658 | + EXPECT_EQ(HcommCcuVariableGetAddr(0xDEADBEEF, 0, &va), CcuResult::CCU_E_NOT_FOUND); | ||
| 1659 | + EXPECT_EQ(HcommCcuEventGetAddr(0xDEADBEEF, 0, &va), CcuResult::CCU_E_NOT_FOUND); | ||
| 1660 | + | ||
| 1661 | + ccuRet = HcommCcuVariableAlloc(insHandle, fakeDieId, validNum, &varHandle); | ||
| 1662 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1663 | + EXPECT_NE(varHandle, 0U); | ||
| 1664 | + EXPECT_EQ(HcommCcuVariableGetAddr(varHandle, 0, nullptr), CcuResult::CCU_E_PTR); | ||
| 1665 | + // 用 variable 的预约句柄去查 event 地址,类型不符应失败 | ||
| 1666 | + EXPECT_EQ(HcommCcuEventGetAddr(varHandle, 0, &va), CcuResult::CCU_E_PARA); | ||
| 1667 | + | ||
| 1668 | + ccuRet = HcommCcuInsDestroy(insHandle); | ||
| 1669 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1670 | +} | ||
| 1671 | + | ||
| 1672 | +TEST_F(HcommCcuControlApiTest, Ut_HcommCcuVariableAlloc_When_MapAddrFailed_Expect_RollbackAll) | ||
| 1673 | +{ | ||
| 1674 | + CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | ||
| 1675 | + constexpr uint32_t fakeDevId = MAX_MODULE_DEVICE_NUM - 16; | ||
| 1676 | + constexpr hcomm::CcuVersion fakeCcuVersion = hcomm::CcuVersion::CCU_V1; | ||
| 1677 | + const int32_t fakeDeviceLogicId = MockCcuDeviceEnv(fakeDevId, fakeCcuVersion); | ||
| 1678 | + | ||
| 1679 | + constexpr auto MS_INS_TPYE = CcuInstanceType::CCU_MS; | ||
| 1680 | + CcuInsHandle insHandle{0}; | ||
| 1681 | + ccuRet = HcommCcuInsCreateLegacy(MS_INS_TPYE, &insHandle); | ||
| 1682 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1683 | + | ||
| 1684 | + auto *ccuIns = hcomm::CcuInstanceMgr::GetInstance(fakeDeviceLogicId).Get(insHandle); | ||
| 1685 | + ASSERT_NE(ccuIns, nullptr); | ||
| 1686 | + auto *resPack = ccuIns->GetResPack(); | ||
| 1687 | + ASSERT_NE(resPack, nullptr); | ||
| 1688 | + | ||
| 1689 | + constexpr uint8_t fakeDieId = 0; | ||
| 1690 | + const std::vector<hcomm::ResInfo> poolBefore = resPack->GetCcuResRepo().blockXn[fakeDieId]; | ||
| 1691 | + auto &resMgr = hcomm::CcuVarEventResMgr::GetInstance(fakeDeviceLogicId); | ||
| 1692 | + const size_t resMapSizeBefore = resMgr.resMap_.size(); | ||
| 1693 | + | ||
| 1694 | + // 第 1 个资源映射成功、第 2 个起失败,触发已映射资源的逐个解映射 + 整笔归还 | ||
| 1695 | + MOCKER(rtGetDevResAddress).stubs() | ||
| 1696 | + .will(returnValue(static_cast<rtError_t>(RT_ERROR_NONE))) | ||
| 1697 | + .then(returnValue(static_cast<rtError_t>(0xFFFFFFFF))); | ||
| 1698 | + // 已成功映射的那 1 个资源必须被精确解映射:次数由 TearDown 的 GlobalMockObject::verify 校验 | ||
| 1699 | + MOCKER(rtReleaseDevResAddress).expects(exactly(1)) | ||
| 1700 | + .will(returnValue(static_cast<rtError_t>(RT_ERROR_NONE))); | ||
| 1701 | + | ||
| 1702 | + constexpr uint32_t varNum = 4; | ||
| 1703 | + CcuVariableHandle varHandle{0xFFFF}; | ||
| 1704 | + ccuRet = HcommCcuVariableAlloc(insHandle, fakeDieId, varNum, &varHandle); | ||
| 1705 | + EXPECT_EQ(ccuRet, CcuResult::CCU_E_RUNTIME); | ||
| 1706 | + | ||
| 1707 | + // 回滚后:出参不得残留句柄,登记表不得残留记录,资源池必须完全恢复 | ||
| 1708 | + EXPECT_EQ(varHandle, 0U); | ||
| 1709 | + EXPECT_EQ(resMgr.resMap_.size(), resMapSizeBefore); | ||
| 1710 | + | ||
| 1711 | + const std::vector<hcomm::ResInfo> &poolAfter = resPack->GetCcuResRepo().blockXn[fakeDieId]; | ||
| 1712 | + uint32_t totalBefore = 0; | ||
| 1713 | + for (const auto &info : poolBefore) { | ||
| 1714 | + totalBefore += info.num; | ||
| 1715 | + } | ||
| 1716 | + uint32_t totalAfter = 0; | ||
| 1717 | + for (const auto &info : poolAfter) { | ||
| 1718 | + totalAfter += info.num; | ||
| 1719 | + } | ||
| 1720 | + EXPECT_EQ(totalAfter, totalBefore); | ||
| 1721 | + | ||
| 1722 | + ccuRet = HcommCcuInsDestroy(insHandle); | ||
| 1723 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1724 | +} | ||
| 1725 | + | ||
| 1726 | +// 前几条用例都经 HcommCcuInsCreateLegacy 建实例,走 CcuInstanceMgr::CreateByInsType; | ||
| 1727 | +// 本例改走 HcommCcuInsCreate(落到 CreateByResDescs)。两条路径都必须把实例句柄回填给 | ||
| 1728 | +// CcuInstance,否则析构时 ReleaseByInstance 拿到的 insHandle_ 为 0,匹配不到任何预约记录, | ||
| 1729 | +// 预约的 XN/CKE 既不解映射也不还池——不报错、只泄漏。用「解映射次数」与「登记表是否清空」 | ||
| 1730 | +// 两个可观测量把这条约束钉住。 | ||
| 1731 | +TEST_F(HcommCcuControlApiTest, Ut_HcommCcuVarEventAlloc_When_InsCreateByResDescs_Expect_ReleaseOnInsDestroy) | ||
| 1732 | +{ | ||
| 1733 | + CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | ||
| 1734 | + constexpr uint32_t fakeDevId = MAX_MODULE_DEVICE_NUM - 17; | ||
| 1735 | + constexpr hcomm::CcuVersion fakeCcuVersion = hcomm::CcuVersion::CCU_V1; | ||
| 1736 | + const int32_t fakeDeviceLogicId = MockCcuDeviceEnv(fakeDevId, fakeCcuVersion); | ||
| 1737 | + | ||
| 1738 | + HcommCcuResDescHandle resDescs[hcomm::CCU_MAX_IODIE_NUM] = {0, 0}; | ||
| 1739 | + CreateCcuResDescsPair(resDescs, fakeCcuVersion); | ||
| 1740 | + constexpr uint32_t descNum = 2; | ||
| 1741 | + CcuInsHandle insHandle{0}; | ||
| 1742 | + ccuRet = HcommCcuInsCreate(resDescs, descNum, &insHandle); | ||
| 1743 | + ASSERT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1744 | + | ||
| 1745 | + constexpr uint8_t fakeDieId = 0; | ||
| 1746 | + constexpr uint32_t varNum = 4; | ||
| 1747 | + constexpr uint32_t eventNum = 2; | ||
| 1748 | + // 预约期每个资源各注册一次 VA,实例析构时必须一一解映射;次数由 TearDown 的 | ||
| 1749 | + // GlobalMockObject::verify 校验,漏调 SetHandle 时这里会是 0 次 | ||
| 1750 | + MOCKER(rtReleaseDevResAddress).expects(exactly(varNum + eventNum)) | ||
| 1751 | + .will(returnValue(static_cast<rtError_t>(RT_ERROR_NONE))); | ||
| 1752 | + | ||
| 1753 | + CcuVariableHandle varHandle{0}; | ||
| 1754 | + ASSERT_EQ(HcommCcuVariableAlloc(insHandle, fakeDieId, varNum, &varHandle), | ||
| 1755 | + CcuResult::CCU_SUCCESS); | ||
| 1756 | + CcuEventHandle eventHandle{0}; | ||
| 1757 | + ASSERT_EQ(HcommCcuEventAlloc(insHandle, fakeDieId, eventNum, &eventHandle), | ||
| 1758 | + CcuResult::CCU_SUCCESS); | ||
| 1759 | + | ||
| 1760 | + auto &resMgr = hcomm::CcuVarEventResMgr::GetInstance(fakeDeviceLogicId); | ||
| 1761 | + ASSERT_NE(resMgr.resMap_.find(varHandle), resMgr.resMap_.end()); | ||
| 1762 | + ASSERT_NE(resMgr.resMap_.find(eventHandle), resMgr.resMap_.end()); | ||
| 1763 | + | ||
| 1764 | + ccuRet = HcommCcuInsDestroy(insHandle); | ||
| 1765 | + EXPECT_EQ(ccuRet, CcuResult::CCU_SUCCESS); | ||
| 1766 | + | ||
| 1767 | + // 实例销毁后两条预约记录都不得残留 | ||
| 1768 | + EXPECT_EQ(resMgr.resMap_.find(varHandle), resMgr.resMap_.end()); | ||
| 1769 | + EXPECT_EQ(resMgr.resMap_.find(eventHandle), resMgr.resMap_.end()); | ||
| 1770 | + | ||
| 1771 | + DestroyCcuResDescs(resDescs); | ||
| 1772 | +} | ||
| 1773 | + | ||
| 1430 | TEST_F(HcommCcuControlApiTest, Ut_HcommCcuKernelAllGatherMesh1dMem2Mem_When_AllFine_Expect_ReturnCcuSUCCESS) | 1774 | TEST_F(HcommCcuControlApiTest, Ut_HcommCcuKernelAllGatherMesh1dMem2Mem_When_AllFine_Expect_ReturnCcuSUCCESS) |
| 1431 | { | 1775 | { |
| 1432 | CcuResult ccuRet = CcuResult::CCU_E_RESERVED; | 1776 | CcuResult ccuRet = CcuResult::CCU_E_RESERVED; |
| @@ -66,5 +66,14 @@ rtError_t rtReleaseDevResAddress(rtDevResInfo * const resInfo) | |||
| 66 | 66 | ||
| 67 | rtError_t rtGetDevResAddress(rtDevResInfo * const resInfo, rtDevResAddrInfo * const addrInfo) | 67 | rtError_t rtGetDevResAddress(rtDevResInfo * const resInfo, rtDevResAddrInfo * const addrInfo) |
| 68 | { | 68 | { |
| 69 | + if (resInfo == nullptr || addrInfo == nullptr || | ||
| 70 | + addrInfo->resAddress == nullptr || addrInfo->len == nullptr) { | ||
| 71 | + return static_cast<rtError_t>(0xFFFFFFFF); | ||
| 72 | + } | ||
| 73 | + // 合成一个非0映射地址,按resId偏移,便于UT校验 | ||
| 74 | + constexpr uint64_t stubResBaseAddr = 0x100000000ULL; | ||
| 75 | + constexpr uint64_t stubResPerSize = 0x1000ULL; | ||
| 76 | + *addrInfo->resAddress = stubResBaseAddr + static_cast<uint64_t>(resInfo->resId) * stubResPerSize; | ||
| 77 | + *addrInfo->len = static_cast<uint32_t>(stubResPerSize); | ||
| 69 | return RT_ERROR_NONE; | 78 | return RT_ERROR_NONE; |
| 70 | } | 79 | } |


[LOW] Array 构造函数错误路径字符串拼接可优化
问题分析:
+操作符拼接字符串,会产生多个临时对象std::string errMsg = "Array creation failed at index " + std::to_string(i) + ", requested count=" + std::to_string(count) + "; the acquire handle likely holds fewer resources than count";建议修复: 使用
std::ostringstream或fmt::format(如果可用)优化字符串拼接。说明:这是微优化,在错误路径上影响不大。