Line data Source code
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};
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(
70 : CcuInsHandle insHandle, CcuResRepository& resRepo, CcuVarEventType type, uint8_t dieId, uint32_t num,
71 : uint64_t& handle);
72 : CcuResult GetVariableXnId(uint64_t handle, uint32_t index, uint8_t& dieId, uint32_t& xnId) const;
73 : CcuResult GetEventCkeId(uint64_t handle, uint32_t index, uint8_t& dieId, uint32_t& ckeId) const;
74 : // 保存 Alloc 阶段为该 handle 注册好的全部资源 VA(下标与资源 index 一一对应)
75 : CcuResult SaveAddrs(CcuVarEventType type, uint64_t handle, const std::vector<uint64_t>& vaList);
76 : // 返回 Alloc 阶段已注册的第 index 个资源 VA
77 : CcuResult GetSavedAddr(CcuVarEventType type, uint64_t handle, uint32_t index, uint64_t& va) const;
78 : CcuResult ReleaseByHandle(uint64_t handle);
79 : CcuResult ReleaseByInstance(CcuInsHandle insHandle);
80 : CcuResult ExcludeAllocatedFromRepo(CcuInsHandle insHandle) const;
81 :
82 : private:
83 132 : explicit CcuVarEventResMgr() = default;
84 132 : ~CcuVarEventResMgr() = default;
85 :
86 : CcuVarEventResMgr(const CcuVarEventResMgr& that) = delete;
87 : CcuVarEventResMgr& operator=(const CcuVarEventResMgr& that) = delete;
88 :
89 : // 校验参数、选池、切出连续块并登记到 resMap_,成功时经 newHandle 返回新句柄
90 : CcuResult AllocAndRecord(
91 : CcuInsHandle insHandle, CcuResRepository& resRepo, CcuVarEventType type, uint8_t dieId, uint32_t num,
92 : uint64_t& newHandle);
93 : // 为 handle 名下 num 个资源逐个注册进程可访问 VA 并缓存;失败时解除本次已完成的映射,
94 : // 资源池的归还由 Acquire 与切池动作配对完成
95 : CcuResult RegisterAddrs(CcuVarEventType type, uint64_t handle, uint32_t num);
96 :
97 : static CcuResult AllocFromPool(std::vector<ResInfo>& pool, uint32_t num, std::vector<ResInfo>& out);
98 : static void ReturnToPool(std::vector<ResInfo>& pool, const std::vector<ResInfo>& res);
99 : // 释放资源前,将 Alloc 阶段映射的进程可访问 VA 逐个 unmap(仅处理已保存 VA 的资源);
100 : // 返回首个 unmap 失败的错误码,失败不中断,其余资源继续 unmap
101 : static CcuResult UnmapSavedAddrs(const CcuVarEventRes& res);
102 :
103 : int32_t devLogicId_{-1};
104 : uint64_t handleSeed_{0};
105 : mutable std::shared_timed_mutex mapMutex_;
106 : std::unordered_map<uint64_t, CcuVarEventRes> resMap_{};
107 : };
108 :
109 : } // namespace hcomm
110 :
111 : #endif // HCOMM_CCU_VAR_EVENT_RES_MGR_H
|