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