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 "global_mem_manager.h"
12 :
13 : #include <string>
14 : #include "hccl_mem.h"
15 :
16 : namespace hccl {
17 135 : GlobalMemRegMgr::~GlobalMemRegMgr()
18 : {
19 135 : }
20 :
21 54 : GlobalMemRegMgr& GlobalMemRegMgr::GetInstance()
22 : {
23 : // reserve 1 instance for invalid deviceid and host
24 186 : static GlobalMemRegMgr instance[MAX_MODULE_DEVICE_NUM + 1];
25 54 : s32 deviceLogicID = 0;
26 :
27 54 : HcclResult hcclRet = hrtGetDeviceRefresh(&deviceLogicID);
28 54 : if (hcclRet != HCCL_SUCCESS) {
29 0 : HCCL_RUN_WARNING("GlobalMemRegMgr::GetInstance hrtGetDeviceRefresh failed, ret[%d], "
30 : "return reserve instance", hcclRet);
31 0 : return instance[MAX_MODULE_DEVICE_NUM];
32 : }
33 :
34 54 : if (static_cast<u32>(deviceLogicID) >= MAX_MODULE_DEVICE_NUM || deviceLogicID <= HOST_DEVICE_ID) {
35 0 : HCCL_RUN_WARNING("[Get][Instance]deviceLogicID[%d] is invalid, return reserve instance", deviceLogicID);
36 0 : return instance[MAX_MODULE_DEVICE_NUM];
37 : }
38 :
39 54 : HCCL_INFO("GlobalMemRegMgr::GetInstance deviceLogicID[%d].", deviceLogicID);
40 54 : return instance[deviceLogicID];
41 : }
42 :
43 2 : HcclResult GlobalMemRegMgr::Destroy()
44 : {
45 2 : HCCL_INFO("[GlobalMemRegMgr][%s] start.", __func__);
46 2 : std::unique_lock<std::mutex> lock(netDevCtxMtx_);
47 2 : for (auto& pair : netDevCtxMap_) {
48 0 : if (pair.second.first == NicType::DEVICE_NIC_TYPE) {
49 0 : socketManager_->ServerDeInit(pair.first.ip, pair.first.listenPort);
50 : }
51 0 : HcclNetCloseDev(pair.second.second);
52 0 : HCCL_INFO("[GlobalMemRegMgr][%s] Close netdev[%p].", __func__, pair.second.second);
53 : }
54 2 : netDevCtxMap_.clear();
55 2 : lock.unlock();
56 2 : CHK_RET(DeInitNic());
57 2 : HCCL_INFO("[GlobalMemRegMgr][%s] end.", __func__);
58 2 : return HCCL_SUCCESS;
59 2 : }
60 :
61 8 : HcclResult GlobalMemRegMgr::CheckOverlapAndInsert(GlobalMemRecord& memRecord, void** memRecordHandle)
62 : {
63 : // 由于每次插入都会保证不产生重叠,所以只需要检查最接近的两条记录是否有重叠即可
64 8 : const auto memInfo = memRecord.PrintInfo();
65 :
66 8 : auto it = memRecordSet_.lower_bound(memRecord);
67 8 : if (it != memRecordSet_.cend()) {
68 3 : if (memRecord == *it) {
69 : // 已经存在相同的记录,取出地址作为handle
70 0 : *memRecordHandle = const_cast<GlobalMemRecord*>(&(*it));
71 0 : HCCL_INFO("[GlobalMemRegMgr][CheckOverlapAndInsert] The memory[%s] has been registered already.",
72 : memInfo.c_str());
73 0 : return HCCL_SUCCESS;
74 : }
75 :
76 : // 检查后一个记录
77 3 : if (memRecord.HasOverlap(*it)) {
78 : // 后一个记录有重叠,报错
79 1 : HCCL_ERROR(
80 : "[GlobalMemRegMgr][CheckOverlapAndInsert] The new memory[%s] overlaps with an existing memory[%s].",
81 : memInfo.c_str(), (*it).PrintInfo().c_str());
82 1 : return HCCL_E_PARA;
83 : }
84 : }
85 :
86 : // 检查前一个记录
87 7 : if (it != memRecordSet_.cbegin()) {
88 2 : auto prevIt = std::prev(it);
89 2 : if (memRecord.HasOverlap(*prevIt)) {
90 : // 前一个记录有重叠,报错
91 1 : HCCL_ERROR(
92 : "[GlobalMemRegMgr][CheckOverlapAndInsert] The new memory[%s] overlaps with an existing memory[%s].",
93 : memInfo.c_str(), (*prevIt).PrintInfo().c_str());
94 1 : return HCCL_E_PARA;
95 : }
96 : }
97 :
98 : // 没有重叠,插入在当前it附近的位置
99 6 : auto insertIt = memRecordSet_.insert(it, std::move(memRecord));
100 :
101 : // 取出地址作为handle
102 6 : *memRecordHandle = const_cast<GlobalMemRecord*>(&(*insertIt));
103 :
104 6 : return HCCL_SUCCESS;
105 8 : }
106 :
107 10 : HcclResult GlobalMemRegMgr::Reg(const HcclMem* mem, void** memRecordHandle)
108 : {
109 : // 不允许注册空内存,报错退出
110 10 : CHK_PTR_NULL(mem);
111 10 : CHK_PRT_RET(mem->addr == nullptr,
112 : HCCL_ERROR("[GlobalMemRegMgr][Reg] The address of mem[%p] to register is null.", mem),
113 : HCCL_E_PARA);
114 9 : CHK_PRT_RET(mem->size == 0,
115 : HCCL_ERROR("[GlobalMemRegMgr][Reg] The size of mem[%p] to register is 0.", mem),
116 : HCCL_E_PARA);
117 :
118 8 : GlobalMemRecord newRecord(mem);
119 8 : const auto memInfo = newRecord.PrintInfo();
120 8 : std::unique_lock<std::mutex> lock(lock_);
121 8 : CHK_RET(CheckOverlapAndInsert(newRecord, memRecordHandle));
122 6 : HCCL_INFO("[GlobalMemRegMgr][Reg] Added a new memory record[%s], handle[%p].",
123 : memInfo.c_str(), *memRecordHandle);
124 :
125 : // 记录地址,便于其他接口进行入参handle合法性校验
126 6 : validHandlePtrSet.emplace(*memRecordHandle);
127 :
128 6 : return HCCL_SUCCESS;
129 8 : }
130 :
131 5 : HcclResult GlobalMemRegMgr::DeReg(void *memRecordHandle)
132 : {
133 5 : const auto *memRecordPtr = static_cast<GlobalMemRecord *>(memRecordHandle);
134 5 : const auto memInfo = memRecordPtr->PrintInfo();
135 5 : std::unique_lock<std::mutex> lock(lock_);
136 :
137 : // 先找到指向这个记录的迭代器
138 5 : const auto it = memRecordSet_.find(*memRecordPtr);
139 5 : if (it == memRecordSet_.cend()) {
140 : // 找不到记录报错退出
141 1 : HCCL_ERROR("[GlobalMemRegMgr][DeReg] Cannot found the corresponding record of memory[%s].", memInfo.c_str());
142 1 : return HCCL_E_NOT_FOUND;
143 : }
144 :
145 : // 检查内存记录是否还与通信域绑定
146 4 : if (memRecordPtr->IsBeingBound()) {
147 : // 该内存还与一个或多个通信域绑定,报错并打印绑定的信息
148 1 : const auto boundComm = memRecordPtr->GetBoundComm();
149 1 : HCCL_ERROR(
150 : "[GlobalMemRegMgr][DeReg] Cannot deregistor memory[%s] since it is still bound to comm(s) listed below:",
151 : memInfo.c_str());
152 :
153 2 : for (const auto &commIdentifier : boundComm) {
154 1 : HCCL_ERROR("[GlobalMemRegMgr][DeReg][bound comm] %s", commIdentifier.c_str());
155 : }
156 :
157 1 : HCCL_ERROR("[GlobalMemRegMgr][DeReg] Please unbind from all bound comm first.");
158 1 : return HCCL_E_PARA;
159 1 : }
160 3 : HcclResult ret = HCCL_SUCCESS;
161 3 : auto regBufInfo = memRecordPtr->GetAllRegBufInfo();
162 3 : for (auto &pair : regBufInfo) {
163 : do {
164 0 : ret = HcclMemDereg(&pair.second); // 需循环调用DeregMem解注册注册内存(一块内存多次Reg的情况,内部有计数)
165 0 : CHK_PRT_CONT(ret != HCCL_SUCCESS && ret != HCCL_E_AGAIN,
166 : HCCL_ERROR("[GlobalMemRegMgr][DeReg] Dereg global mem failed, addr[%p] size[%lu].",
167 : pair.second.addr, pair.second.len));
168 0 : } while (ret == HCCL_E_AGAIN);
169 : }
170 :
171 : // 清除记录,析构时会触发网络设备的解注册
172 3 : memRecordSet_.erase(it);
173 3 : HCCL_INFO("[GlobalMemRegMgr][DeReg] Memory[%s] has been deregistered.", memInfo.c_str());
174 :
175 : // 当内存全部解注册后,主动释放网络资源
176 3 : if (memRecordSet_.empty()) {
177 2 : CHK_RET(Destroy());
178 : }
179 :
180 3 : validHandlePtrSet.erase(memRecordHandle);
181 3 : return HCCL_SUCCESS;
182 5 : }
183 :
184 17 : HcclResult GlobalMemRegMgr::InitNic()
185 : {
186 17 : std::lock_guard<std::mutex> lock(netDevCtxMtx_);
187 17 : if (nicInited_) {
188 15 : HCCL_INFO("[InitNic] Nic has been inited. devicePhyId[%u], deviceLogicId[%d]", devicePhyId_, deviceLogicId_);
189 15 : return HCCL_SUCCESS;
190 : }
191 :
192 2 : if (devicePhyId_ == INVALID_UINT || deviceLogicId_ == INVALID_INT) {
193 1 : CHK_RET(hrtGetDevice(&deviceLogicId_));
194 1 : CHK_RET(hrtGetDevicePhyIdByIndex(static_cast<u32>(deviceLogicId_), devicePhyId_));
195 : }
196 2 : CHK_RET(HcclNetInit(NICDeployment::NIC_DEPLOYMENT_DEVICE, devicePhyId_, static_cast<u32>(deviceLogicId_), false));
197 2 : nicInited_ = true;
198 2 : socketManager_.reset(new (std::nothrow) HcclSocketManager(NICDeployment::NIC_DEPLOYMENT_DEVICE, deviceLogicId_, devicePhyId_, 0));
199 2 : CHK_PTR_NULL(socketManager_);
200 2 : HCCL_INFO("[InitNic] Nic init success, devicePhyId[%u], deviceLogicId[%d]", devicePhyId_, deviceLogicId_);
201 2 : return HCCL_SUCCESS;
202 17 : }
203 :
204 4 : HcclResult GlobalMemRegMgr::DeInitNic()
205 : {
206 4 : if (!nicInited_) {
207 2 : HCCL_INFO(
208 : "[DeInitNic] Nic has been deinited. devicePhyId[%u], deviceLogicId[%d]", devicePhyId_, deviceLogicId_);
209 2 : return HCCL_SUCCESS;
210 : }
211 :
212 2 : if (devicePhyId_ == INVALID_UINT || deviceLogicId_ == INVALID_INT) {
213 0 : CHK_RET(hrtGetDevice(&deviceLogicId_));
214 0 : CHK_RET(hrtGetDevicePhyIdByIndex(static_cast<u32>(deviceLogicId_), devicePhyId_));
215 : }
216 2 : CHK_RET(HcclNetDeInit(NICDeployment::NIC_DEPLOYMENT_DEVICE, devicePhyId_, static_cast<u32>(deviceLogicId_)));
217 2 : nicInited_ = false;
218 2 : HCCL_INFO("[DeInitNic] Nic deinit success. devicePhyId[%u], deviceLogicId[%d]", devicePhyId_, deviceLogicId_);
219 2 : return HCCL_SUCCESS;
220 : }
221 :
222 1 : HcclResult GlobalMemRegMgr::CheckOneSidedBackupAndSetDevId(const HcclIpAddress &ipAddr, u32 &backupDevPhyId, u32 &backupDevLogicId,
223 : std::vector<HcclIpAddress> &localIpList, bool &isOneSidedTaskAndBackupInitA3)
224 : {
225 1 : DevType deviceType = DevType::DEV_TYPE_COUNT;
226 1 : CHK_RET(hrtGetDeviceType(deviceType));
227 1 : if (deviceType != DevType::DEV_TYPE_910_93) {
228 0 : isOneSidedTaskAndBackupInitA3 = false;
229 0 : HCCL_INFO("[GlobalMemRegMgr::CheckOneSidedBackupAndSetDevId] deviceType[%d] is not 910_93, One sided backup not support",
230 : static_cast<u32>(deviceType));
231 0 : return HCCL_SUCCESS;
232 : }
233 1 : CHK_RET(hrtGetPairDevicePhyId(devicePhyId_, backupDevPhyId));
234 1 : CHK_RET(hrtRaGetDeviceIP(devicePhyId_, localIpList));
235 1 : std::vector<HcclIpAddress> backupIpList;
236 1 : std::vector<std::vector<HcclIpAddress>> chipDeviceIPs;
237 1 : CHK_RET(hrtRaGetDeviceAllNicIP(chipDeviceIPs));
238 1 : if (chipDeviceIPs.empty()) {
239 0 : HCCL_RUN_WARNING("[GlobalMemRegMgr::CheckOneSidedBackupAndSetDevId] chipDeviceIPs is empty, system nic ip may not set.");
240 0 : isOneSidedTaskAndBackupInitA3 = false;
241 0 : return HCCL_SUCCESS;
242 : }
243 1 : u32 ipIdex = 1U - (devicePhyId_ % 2U);
244 1 : std::copy_if(chipDeviceIPs[ipIdex].begin(), chipDeviceIPs[ipIdex].end(),
245 1 : std::back_inserter(backupIpList), [](const HcclIpAddress& ip) { return !ip.IsIPv6(); });
246 1 : auto equalToLocal = [&ipAddr](const HcclIpAddress &entry) { return entry == ipAddr;};
247 1 : isOneSidedTaskAndBackupInitA3 = !std::any_of(localIpList.begin(), localIpList.end(), equalToLocal) &&
248 0 : std::any_of(backupIpList.begin(), backupIpList.end(), equalToLocal);
249 1 : if (isOneSidedTaskAndBackupInitA3) {
250 0 : CHK_RET(hrtGetDeviceIndexByPhyId(backupDevPhyId, backupDevLogicId));
251 : }
252 1 : HCCL_INFO("[GlobalMemRegMgr::CheckOneSidedBackupAndSetDevI]devicePhysicID[%u], localIpList[%s], backupDevPhyId[%d], backupDeviceIP[0]:[%s],"
253 : "isOneSidedTaskAndBackupInitA3[%s]", devicePhyId_, localIpList[0].GetReadableAddress(), backupDevPhyId, backupIpList[0].GetReadableAddress(),
254 : isOneSidedTaskAndBackupInitA3 ? "true" : "false");
255 1 : return HCCL_SUCCESS;
256 1 : }
257 :
258 :
259 1 : HcclResult GlobalMemRegMgr::GetNetDevCtx(NicType nicType, const HcclIpAddress &ipAddr, u32 port,
260 : HcclNetDevCtx &netDevCtx)
261 : {
262 1 : if (devicePhyId_ == INVALID_UINT || deviceLogicId_ == INVALID_INT) {
263 1 : CHK_RET(hrtGetDevice(&deviceLogicId_));
264 1 : CHK_RET(hrtGetDevicePhyIdByIndex(static_cast<u32>(deviceLogicId_), devicePhyId_));
265 : }
266 1 : HCCL_INFO("[GlobalMemRegMgr][GetNetDevCtx] nicType[%d], ip[%s]", nicType, ipAddr.GetReadableAddress());
267 :
268 1 : u32 backupDevPhyId = INVALID_INT;
269 1 : u32 backupDevLogicId = INVALID_INT;
270 1 : bool isOneSidedTaskAndBackupInitA3 = false;
271 1 : std::vector<HcclIpAddress> localIpList;
272 1 : CHK_RET(CheckOneSidedBackupAndSetDevId(ipAddr, backupDevPhyId, backupDevLogicId, localIpList, isOneSidedTaskAndBackupInitA3));
273 1 : HCCL_INFO("[GlobalMemRegMgr][GetNetDevCtx] nicType[%d], ip[%s], port[%u]", nicType, ipAddr.GetReadableAddress(),
274 : port);
275 :
276 1 : std::lock_guard<std::mutex> lock(netDevCtxMtx_);
277 : // 进程粒度open dev,如果已open,直接复用
278 1 : PortInfo portInfo(ipAddr, port);
279 1 : if (netDevCtxMap_.find(portInfo) != netDevCtxMap_.end()) {
280 0 : netDevCtx = netDevCtxMap_[portInfo].second;
281 0 : CHK_PTR_NULL(netDevCtx);
282 0 : return HCCL_SUCCESS;
283 : }
284 : HcclNetDevCtx tempNetDevCtx;
285 1 : if (isOneSidedTaskAndBackupInitA3) {
286 0 : HCCL_INFO("[GlobalMemRegMgr::GetNetDevCtx] OneSeidedService backupInit: backupDevPhyId[%d], backupDevLogicId[%d], localIp[%s], backupIp[%s]",
287 : backupDevPhyId, backupDevLogicId, localIpList[0].GetReadableAddress(), ipAddr.GetReadableAddress());
288 0 : CHK_RET(HcclNetInit(NICDeployment::NIC_DEPLOYMENT_DEVICE, backupDevPhyId, backupDevLogicId, false, true));
289 0 : CHK_RET(HcclNetInit(NICDeployment::NIC_DEPLOYMENT_DEVICE, devicePhyId_, static_cast<u32>(deviceLogicId_), false));
290 0 : CHK_RET(HcclNetOpenDev(&tempNetDevCtx, nicType, backupDevPhyId, backupDevLogicId, ipAddr, localIpList[0]));
291 : } else {
292 1 : CHK_RET(HcclNetOpenDev(&tempNetDevCtx, nicType, devicePhyId_, deviceLogicId_, ipAddr));
293 : }
294 1 : CHK_PTR_NULL(tempNetDevCtx);
295 1 : netDevCtxMap_.insert(std::make_pair(portInfo, std::make_pair(nicType, tempNetDevCtx)));
296 1 : netDevCtx = tempNetDevCtx;
297 1 : if (nicType == NicType::DEVICE_NIC_TYPE) {
298 1 : CHK_RET(socketManager_->ServerInit(netDevCtx, port));
299 : }
300 1 : HCCL_INFO(
301 : "[GlobalMemRegMgr][GetNetDevCtx] nicType[%d] ip[%s] has been Init.", nicType, ipAddr.GetReadableAddress());
302 1 : return HCCL_SUCCESS;
303 1 : }
304 :
305 : } // namespace hccl
|