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 <memory>
12 : #include "hccl_common.h"
13 : #include "stream_pub.h"
14 : #include "aicpu/aicpu_hccl_sqcqv1.h"
15 : #include "aicpu/aicpu_hccl_sqcqv2.h"
16 : #include "config_plf_log.h"
17 : #include "dlhal_function.h"
18 : #include "adapter_hal_pub.h"
19 : #include "adapter_rts.h"
20 : #include "dispatcher_aicpu.h"
21 :
22 : namespace hccl {
23 : constexpr uint64_t NANOSECOND_TO_SECOND = 1000000000U;
24 : constexpr uint16_t TURN_LEFT_SHIFT_BIT = 16;
25 : constexpr uint32_t HCCL_PER_LAUNCH_SQE_CNT = 128U; // 每编排N个SQE,做一次launchtask
26 :
27 : #ifdef __cplusplus
28 : extern "C" {
29 : #endif // __cplusplus
30 : HcclResult
31 11 : HcclDispatcherAicpuInit(HcclDispatcher* dispatcher, const u32 devPhyId, uint32_t hcclQos, DispatcherType type)
32 : {
33 11 : CHK_PTR_NULL(dispatcher);
34 11 : DispatcherPub* pDispatcher = nullptr;
35 11 : if (type == DispatcherType::DISPATCHER_AICPU) {
36 11 : pDispatcher = new (std::nothrow) DispatcherAiCpu(devPhyId);
37 11 : pDispatcher->SetHcclQos(hcclQos);
38 11 : pDispatcher->SetMpamid(0);
39 11 : HCCL_INFO("HcclDispatcherAicpuInit hcclQos = %u", pDispatcher->GetHcclQos());
40 : } else {
41 0 : HCCL_ERROR("[HcclCommAicpu][HcclDispatcherInit] Not support the dispatcher type[%d]", type);
42 0 : return HCCL_E_NOT_SUPPORT;
43 : }
44 11 : CHK_PTR_NULL(pDispatcher);
45 11 : HcclResult ret = pDispatcher->Init();
46 11 : if (ret != HCCL_SUCCESS) {
47 0 : HCCL_ERROR("[HcclCommAicpu][HcclDispatcherInit] Dispatcher init failed, type[%d]", type);
48 0 : delete pDispatcher;
49 0 : pDispatcher = nullptr;
50 0 : return ret;
51 : }
52 11 : *dispatcher = pDispatcher;
53 11 : return HCCL_SUCCESS;
54 : }
55 : #ifdef __cplusplus
56 : }
57 : #endif // __cplusplus
58 :
59 450 : DispatcherAiCpu::DispatcherAiCpu(const u32 devPhyId) // deprecated
60 450 : : DispatcherPub(INVALID_INT)
61 : {
62 449 : aicpuInfo_.devId = devPhyId;
63 449 : }
64 :
65 900 : DispatcherAiCpu::~DispatcherAiCpu() {}
66 :
67 448 : HcclResult DispatcherAiCpu::Init()
68 : {
69 448 : CHK_RET(DlHalFunction::GetInstance().DlHalFunctionInit());
70 449 : CHK_RET(hrtHalGetDeviceType(aicpuInfo_.devId, aicpuInfo_.devType));
71 449 : CHK_RET(hrtHalGetDeviceInfo(
72 : aicpuInfo_.devId, MODULE_TYPE_SYSTEM, INFO_TYPE_PHY_CHIP_ID, reinterpret_cast<int64_t*>(&aicpuInfo_.chipId)));
73 :
74 449 : if (aicpuInfo_.devType == DevType::DEV_TYPE_310P1 || aicpuInfo_.devType == DevType::DEV_TYPE_310P3) {
75 0 : addOneNotifyWaitSqe_ = AddOneNotifyWaitSqeV2;
76 0 : addOneRecordSqe_ = AddOneRecordSqeV2;
77 0 : addOneWriteValueRecordSqe_ = AddOneWriteValueRecordSqeV2;
78 0 : addOneMemcpySqe_ = AddOneMemcpySqeV2;
79 0 : addOneEventResetSqe_ = AddOneEventResetSqeV2;
80 0 : addOneEventRecordSqe_ = AddOneEventRecordSqeV2;
81 0 : addOneEventWaitSqe_ = AddOneEventWaitSqeV2;
82 : } else {
83 449 : addOneNotifyWaitSqe_ = AddOneNotifyWaitSqeV1;
84 449 : addOneRecordSqe_ = AddOneRecordSqeV1;
85 449 : addOneWriteValueRecordSqe_ = AddOneWriteValueRecordSqeV1;
86 449 : addOneMemcpySqe_ = AddOneMemcpySqeV1;
87 449 : addOneEventResetSqe_ = AddOneEventResetSqeV1;
88 449 : addOneEventRecordSqe_ = AddOneEventRecordSqeV1;
89 449 : addOneEventWaitSqe_ = AddOneEventWaitSqeV1;
90 449 : addOneRdmaDbSendSqe_ = AddOneRdmaDbSendSqeV1;
91 449 : addOneFlipPlaceHolderSqe_ = AddOneFlipPlaceHolderSqeV1;
92 449 : addOneCacheMemcpyPlaceHolderSqe_ = AddOneCacheMemcpyPlaceHolderSqeV1;
93 449 : addOneCacheNotifyWaitPlaceholderSqe_ = AddOneCacheNotifyWaitPlaceholderSqeV1;
94 449 : addOneCacheNotifyRecordPlaceholderSqe_ = AddOneCacheNotifyRecordPlaceholderSqeV1;
95 449 : addOneCacheWriteValuePlaceholderSqe_ = AddOneCacheWriteValuePlaceholderSqeV1;
96 449 : addOneCacheMemcpyRecordPlaceholderSqe_ = AddOneCacheMemcpyRecordPlaceholderSqeV1;
97 449 : CHK_PTR_NULL(addOneRdmaDbSendSqe_);
98 449 : CHK_PTR_NULL(addOneFlipPlaceHolderSqe_);
99 449 : CHK_PTR_NULL(addOneCacheMemcpyPlaceHolderSqe_);
100 449 : CHK_PTR_NULL(addOneCacheNotifyWaitPlaceholderSqe_);
101 449 : CHK_PTR_NULL(addOneCacheNotifyRecordPlaceholderSqe_);
102 449 : CHK_PTR_NULL(addOneCacheWriteValuePlaceholderSqe_);
103 449 : CHK_PTR_NULL(addOneCacheMemcpyRecordPlaceholderSqe_);
104 : }
105 :
106 449 : CHK_PTR_NULL(addOneNotifyWaitSqe_);
107 449 : CHK_PTR_NULL(addOneRecordSqe_);
108 449 : CHK_PTR_NULL(addOneWriteValueRecordSqe_);
109 449 : CHK_PTR_NULL(addOneMemcpySqe_);
110 449 : CHK_PTR_NULL(addOneEventResetSqe_);
111 449 : CHK_PTR_NULL(addOneEventRecordSqe_);
112 449 : CHK_PTR_NULL(addOneEventWaitSqe_);
113 :
114 449 : CHK_RET(GetNotifyMaxWaitTime());
115 : // 和hrtGetNotifySize接口保持一致,910B和910_93的notify寄存器大小为4字节,其他芯片为8字节
116 448 : notifySize_ = (aicpuInfo_.devType == DevType::DEV_TYPE_910B || aicpuInfo_.devType == DevType::DEV_TYPE_910_93) ?
117 : NOTIFY_SIZE_BYTES_910B :
118 : NOTIFY_SIZE_BYTES_910A;
119 448 : InitTimeOutConfig();
120 448 : HCCL_INFO(
121 : "%s success, devId:%u, devType:%d, chipId:%lld", __func__, aicpuInfo_.devId, aicpuInfo_.devType,
122 : aicpuInfo_.chipId);
123 449 : return HCCL_SUCCESS;
124 : }
125 :
126 1 : HcclResult DispatcherAiCpu::WaitValue(hccl::Stream& stream, u64 waitAddr, u64 valueAddr, bool reset)
127 : {
128 1 : u32 turnNum = *(reinterpret_cast<u32*>(static_cast<uintptr_t>(valueAddr)));
129 1 : HCCL_DEBUG("[DispatcherAiCpu][WaitValue] turnNum %u", turnNum);
130 1 : uint8_t* sqeBuffer = nullptr;
131 1 : uint8_t* sqeTypeAddr = nullptr;
132 1 : uint8_t* sqeDfxInfoAddr = nullptr;
133 1 : uint16_t taskId = 0U;
134 1 : CHK_RET(stream.GetNextSqeBufferAddr(sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
135 : const HcclComStreamInfo* streamInfo;
136 1 : CHK_RET(stream.GetStreamInfo(streamInfo));
137 1 : AddOneWaitStartSqe(
138 1 : streamInfo->actualStreamId, taskId, waitAddr, valueAddr, reset,
139 : reinterpret_cast<rtStarsCcoreWaitStartSqe_t*>(sqeBuffer), sqeTypeAddr);
140 1 : HcclSqeContext* sqeCtx = stream.GetSqeContextPtr();
141 1 : if (sqeCtx == nullptr) {
142 0 : HCCL_ERROR("[DispatcherAiCpu][WaitValue] AddCcoreWait sqeCtx is nullptr");
143 0 : return HCCL_E_INTERNAL;
144 : }
145 1 : sqeCtx->buffer.addInfo[taskId % hccl::HCCL_SQE_MAX_CNT]
146 1 : = ((turnNum << TURN_LEFT_SHIFT_BIT) + static_cast<uint32_t>(reset));
147 1 : return HCCL_SUCCESS;
148 : }
149 :
150 1 : HcclResult DispatcherAiCpu::WriteValue(hccl::Stream& stream, u64 writeAddr, u64 valueAddr)
151 : {
152 1 : u32 turnNum = *(reinterpret_cast<u32*>(static_cast<uintptr_t>(valueAddr)));
153 1 : HCCL_DEBUG("[DispatcherAiCpu][WriteValue] turnNum %u", turnNum);
154 1 : uint8_t* sqeBuffer = nullptr;
155 1 : uint8_t* sqeTypeAddr = nullptr;
156 1 : uint8_t* sqeDfxInfoAddr = nullptr;
157 1 : uint16_t taskId = 0U;
158 1 : CHK_RET(stream.GetNextSqeBufferAddr(sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
159 : const HcclComStreamInfo* streamInfo;
160 1 : CHK_RET(stream.GetStreamInfo(streamInfo));
161 1 : AddOneWriteValueStartSqe(
162 1 : streamInfo->actualStreamId, taskId, writeAddr, valueAddr,
163 : reinterpret_cast<rtStarsCcoreWriteValueSqe_t*>(sqeBuffer), sqeTypeAddr);
164 1 : HcclSqeContext* sqeCtx = stream.GetSqeContextPtr();
165 1 : if (sqeCtx == nullptr) {
166 0 : HCCL_ERROR("[DispatcherAiCpu][WriteValue] AddCcoreNotify sqeCtx is nullptr");
167 0 : return HCCL_E_INTERNAL;
168 : }
169 1 : sqeCtx->buffer.addInfo[taskId % hccl::HCCL_SQE_MAX_CNT] = turnNum;
170 1 : return HCCL_SUCCESS;
171 : }
172 :
173 2 : HcclResult DispatcherAiCpu::SignalRecord(
174 : [[maybe_unused]] HcclRtNotify signal, hccl::Stream& stream, u32 userRank, [[maybe_unused]] u64 offset,
175 : [[maybe_unused]] s32 stage, bool inchip, u64 signalAddr, u32 notifyId)
176 : {
177 2 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
178 2 : uint8_t* sqeBuffer = nullptr;
179 2 : uint8_t* sqeTypeAddr = nullptr;
180 2 : uint8_t* sqeDfxInfoAddr = nullptr;
181 2 : uint16_t taskId = 0U;
182 2 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
183 2 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
184 2 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
185 2 : dfxInfo->remoteRank = userRank;
186 2 : dfxInfo->notifyId = notifyId;
187 :
188 : // 检查是否需要生成cache-write placeholder
189 2 : if (isPlaceholder_) {
190 : // 只有使能alltoallv类算子的aicpu cache才需要cache-write placeholder
191 0 : CHK_PRT_RET(
192 : !(needAddSqe_ && isAlltoallv_),
193 : HCCL_ERROR(
194 : "[DispatcherAiCpu][SignalRecord] isPlaceholder_[%u]"
195 : "needAddSqe_[%u] isAlltoallv_[%u]",
196 : isPlaceholder_, needAddSqe_, isAlltoallv_),
197 : HCCL_E_INTERNAL);
198 :
199 : // 只有p2p的SignalRecord才需要cache-write placeholder
200 : // 不需要为inchip场景下LocalNotify::Post的SignalRecord调用addOneCacheNotifyRecordPlaceholderSqe_生成cache-notify
201 : // placeholder
202 0 : CHK_PRT_RET(
203 : inchip,
204 : HCCL_ERROR("[DispatcherAiCpu][SignalRecord] isPlaceholder_[%u], inchip[%u]", isPlaceholder_, inchip),
205 : HCCL_E_INTERNAL);
206 :
207 0 : addOneCacheWriteValuePlaceholderSqe_(streamInfo.actualStreamId, taskId, signalAddr, sqeBuffer, sqeTypeAddr);
208 0 : HCCL_INFO("%s generate cache-write placeholder for signal record", __func__);
209 : } else { // 正常生成SQE
210 2 : if (inchip) {
211 1 : addOneRecordSqe_(streamInfo.actualStreamId, taskId, notifyId, sqeBuffer, sqeTypeAddr);
212 : } else {
213 1 : addOneWriteValueRecordSqe_(streamInfo.actualStreamId, taskId, signalAddr, sqeBuffer, sqeTypeAddr);
214 : }
215 : }
216 :
217 2 : PLF_CONFIG_INFO(
218 : PLF_TASK, "%s para: streamId[%d] remoteRank[%u] inchip[%d] devType[%d] notifyId[%u]", __func__,
219 : streamInfo.actualStreamId, userRank, inchip, aicpuInfo_.devType, notifyId);
220 2 : return HCCL_SUCCESS;
221 : }
222 :
223 1 : HcclResult DispatcherAiCpu::SignalRecord(
224 : hccl::DeviceMem& dst, hccl::DeviceMem& src, hccl::Stream& stream, u32 remoteUserRank, hccl::LinkType inLinkType,
225 : u32 notifyId)
226 : {
227 : // 参数有效性检查
228 1 : CHK_PRT_RET(src.size() == 0, HCCL_INFO("%s src size is 0, not need copy", __func__), HCCL_SUCCESS);
229 1 : CHK_PRT_RET(src == dst, HCCL_INFO("%s src and dst is same, not need copy", __func__), HCCL_SUCCESS);
230 1 : CHK_PRT_RET(
231 : dst.size() < src.size(),
232 : HCCL_ERROR(
233 : "%s The size of dst is smaller than that of src. dst addr:%p, dst size:%llu, src addr:%p, "
234 : "src size:%llu",
235 : __func__, dst.ptr(), dst.size(), src.ptr(), src.size()),
236 : HCCL_E_PARA);
237 1 : CHK_PRT_RET(
238 : src.size() != notifySize_,
239 : HCCL_ERROR(
240 : "%s src size[%llu] should be %llu in devType[%d]", __func__, src.size(), notifySize_, aicpuInfo_.devType),
241 : HCCL_E_PARA);
242 :
243 1 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
244 1 : uint8_t* sqeBuffer = nullptr;
245 1 : uint8_t* sqeTypeAddr = nullptr;
246 1 : uint8_t* sqeDfxInfoAddr = nullptr;
247 1 : uint16_t taskId = 0U;
248 1 : aclrtReduceKind rtReduceOp = RK_MAP_TABLE[HCCL_REDUCE_RESERVED];
249 1 : uint8_t linkType = static_cast<uint8_t>(inLinkType);
250 :
251 1 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
252 1 : AicpuDfxInfo* const dfxInfo = reinterpret_cast<AicpuDfxInfo* const>(sqeDfxInfoAddr);
253 1 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
254 1 : dfxInfo->remoteRank = remoteUserRank;
255 1 : dfxInfo->notifyId = notifyId;
256 :
257 : // 检查是否需要生成cache-memcpy-record placeholder
258 1 : if (isPlaceholder_) {
259 : // 只有使能alltoallv类算子的aicpu cache才需要cache-memcpy-record placeholder
260 0 : CHK_PRT_RET(
261 : !(needAddSqe_ && isAlltoallv_),
262 : HCCL_ERROR(
263 : "[DispatcherAiCpu][SignalRecord] isPlaceholder_[%u]"
264 : "needAddSqe_[%u] isAlltoallv_[%u]",
265 : isPlaceholder_, needAddSqe_, isAlltoallv_),
266 : HCCL_E_INTERNAL);
267 :
268 0 : addOneCacheMemcpyRecordPlaceholderSqe_(
269 0 : streamInfo.actualStreamId, taskId, src.ptr(), src.size(), ACL_FLOAT, rtReduceOp, dst.ptr(), 0,
270 : aicpuInfo_.ssid, aicpuInfo_.devId, aicpuInfo_.overflowAddr, linkType, sqeBuffer, sqeTypeAddr,
271 : SDMA_QOS_DEFAULT);
272 0 : HCCL_INFO("%s generate cache-memcpy-record placeholder for signal record", __func__);
273 : } else { // 正常生成memcpy record SQE
274 3 : addOneMemcpySqe_(
275 1 : streamInfo.actualStreamId, taskId, src.ptr(), src.size(), ACL_FLOAT, rtReduceOp, dst.ptr(), 0,
276 : aicpuInfo_.ssid, aicpuInfo_.devId, aicpuInfo_.overflowAddr, linkType, sqeBuffer, sqeTypeAddr,
277 : SDMA_QOS_DEFAULT);
278 : }
279 :
280 1 : PLF_CONFIG_INFO(
281 : PLF_TASK,
282 : "%s para: linkType[%u] srcPtr[%p] srcSize[%llu] dstPtr[%p] taskId[%u] streamId[%u] remoteRank[%u] notifyId[%u] "
283 : "hcclQos[%u]",
284 : __func__, linkType, src.ptr(), src.size(), dst.ptr(), taskId, streamInfo.actualStreamId, remoteUserRank,
285 : notifyId, SDMA_QOS_DEFAULT);
286 1 : return HCCL_SUCCESS;
287 : }
288 :
289 3 : HcclResult DispatcherAiCpu::SignalWait(
290 : [[maybe_unused]] HcclRtNotify signal, Stream& stream, u32 userRank, u32 remoteUserRank, [[maybe_unused]] s32 stage,
291 : bool inchip, u32 notifyId, u32 timeOut)
292 : {
293 3 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
294 3 : uint8_t* sqeBuffer = nullptr;
295 3 : uint8_t* sqeTypeAddr = nullptr;
296 3 : uint8_t* sqeDfxInfoAddr = nullptr;
297 3 : uint16_t taskId = 0U;
298 3 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
299 3 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
300 3 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
301 3 : dfxInfo->remoteRank = remoteUserRank;
302 3 : dfxInfo->notifyId = notifyId;
303 :
304 3 : dfxTimeOutConfig_.sqeTimeOutTimeOut = timeOut < notifyMaxWaitTime_ ? timeOut : dfxTimeOutConfig_.sqeTimeOutTimeOut;
305 : // 检查是否需要生成cache-notify placeholder
306 3 : if (isPlaceholder_) {
307 : // 只有使能alltoallv类算子的aicpu cache才需要cache-notify placeholder
308 0 : CHK_PRT_RET(
309 : !(needAddSqe_ && isAlltoallv_),
310 : HCCL_ERROR(
311 : "[DispatcherAiCpu][SignalWait] isPlaceholder_[%u]"
312 : "needAddSqe_[%u] isAlltoallv_[%u]",
313 : isPlaceholder_, needAddSqe_, isAlltoallv_),
314 : HCCL_E_INTERNAL);
315 :
316 : // 只有A3下才会使能alltoallv aicpu cache并需要cache-notify placeholder
317 0 : CHK_PRT_RET(
318 : !(inchip
319 : || (aicpuInfo_.devType != DevType::DEV_TYPE_310P1 && aicpuInfo_.devType != DevType::DEV_TYPE_310P3)),
320 : HCCL_ERROR(
321 : "[DispatcherAiCpu][SignalWait] isPlaceholder_[%u] inchip[%u] devType[%u]", isPlaceholder_, inchip,
322 : aicpuInfo_.devType),
323 : HCCL_E_INTERNAL);
324 :
325 0 : addOneCacheNotifyWaitPlaceholderSqe_(
326 0 : streamInfo.actualStreamId, taskId, notifyId, sqeBuffer, sqeTypeAddr, dfxTimeOutConfig_);
327 0 : HCCL_INFO("%s generate cache-notify placeholder for signal wait", __func__);
328 : } else { // 正常生成SQE
329 3 : if (inchip
330 2 : || (aicpuInfo_.devType != DevType::DEV_TYPE_310P1 && aicpuInfo_.devType != DevType::DEV_TYPE_310P3)) {
331 3 : addOneNotifyWaitSqe_(
332 3 : streamInfo.actualStreamId, taskId, notifyId, sqeBuffer, sqeTypeAddr, dfxTimeOutConfig_);
333 : } else {
334 0 : u32 notifyRevisedOffset = 15U; // eventid偏移15位后为1
335 0 : u32 notifyGetEventId = 0x3FFU; // 取低15位
336 0 : if ((notifyId >> notifyRevisedOffset) != 0) {
337 0 : addOneEventWaitSqe_(
338 0 : streamInfo.actualStreamId, (notifyId & notifyGetEventId), taskId, sqeBuffer, sqeTypeAddr);
339 :
340 0 : uint8_t* sqeBuffer1 = nullptr;
341 0 : uint8_t* sqeTypeAddr1 = nullptr;
342 0 : uint8_t* sqeDfxInfoAddr1 = nullptr;
343 0 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer1, sqeTypeAddr1, sqeDfxInfoAddr1, taskId));
344 0 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr1;
345 0 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
346 0 : dfxInfo->remoteRank = INVALID_VALUE_RANKID;
347 :
348 0 : u64 addr = 0;
349 0 : addOneEventResetSqe_(
350 0 : streamInfo.actualStreamId, (notifyId & notifyGetEventId), taskId, aicpuInfo_.devId, 0, addr,
351 : sqeBuffer1, sqeTypeAddr1);
352 : } else {
353 0 : HCCL_WARNING("%s SignalWait id is not event, please check %d", __func__, notifyId);
354 : }
355 : }
356 : }
357 :
358 3 : PLF_CONFIG_INFO(
359 : PLF_TASK,
360 : "%s para: streamId[%u] userRank[%u] remoteRank[%u] inchip[%d] devType[%d] notifyId[%u] sqeTimeOutTimeOut[%llu]",
361 : __func__, streamInfo.actualStreamId, userRank, remoteUserRank, inchip, aicpuInfo_.devType, notifyId,
362 : dfxTimeOutConfig_.sqeTimeOutTimeOut);
363 3 : return HCCL_SUCCESS;
364 : }
365 :
366 3 : HcclResult DispatcherAiCpu::MemcpyAsync(
367 : hccl::DeviceMem& dst, const hccl::DeviceMem& src, hccl::Stream& stream, u32 remoteUserRank,
368 : hccl::LinkType inLinkType)
369 : {
370 : // 检查是否需要生成cache-memcpy placeholder
371 3 : if (isPlaceholder_) {
372 : // 只有零长拷贝才需要cache-memcpy placeholder
373 0 : CHK_PRT_RET(
374 : src.size() != 0,
375 : HCCL_ERROR("[DispatcherAiCpu][MemcpyAsync] isPlaceholder_[%u] src.size[%llu]", isPlaceholder_, src.size()),
376 : HCCL_E_INTERNAL);
377 :
378 : // 只有使能alltoallv类算子的aicpu cache才需要cache-memcpy placeholder
379 0 : CHK_PRT_RET(
380 : !(needAddSqe_ && isAlltoallv_),
381 : HCCL_ERROR(
382 : "[DispatcherAiCpu][MemcpyAsync] isPlaceholder_[%u]"
383 : "needAddSqe_[%u] isAlltoallv_[%u]",
384 : isPlaceholder_, needAddSqe_, isAlltoallv_),
385 : HCCL_E_INTERNAL);
386 :
387 : // 准备SQE, sqeType, dfxInfo
388 0 : uint8_t* sqeBuffer = nullptr;
389 0 : uint8_t* sqeTypeAddr = nullptr;
390 0 : uint8_t* sqeDfxInfoAddr = nullptr;
391 0 : uint16_t taskId = 0U;
392 0 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
393 :
394 : // 生成cache-memcpy placeholder SQE, 并设置sqeType
395 0 : CHK_PTR_NULL(addOneCacheMemcpyPlaceHolderSqe_);
396 0 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
397 0 : addOneCacheMemcpyPlaceHolderSqe_(
398 0 : streamInfo.actualStreamId, taskId, src.ptr(), dst.ptr(), static_cast<uint8_t>(inLinkType), sqeBuffer,
399 : sqeTypeAddr, hcclQos_);
400 :
401 : // 设置dfxInfo
402 0 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
403 0 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
404 0 : dfxInfo->remoteRank = remoteUserRank;
405 0 : dfxInfo->notifyId = INVALID_VALUE_RANKID;
406 :
407 0 : HCCL_INFO("%s capture zero-len memcpy for alltoallv, generate cache-memcpy placeholder sqe", __func__);
408 :
409 0 : return HCCL_SUCCESS;
410 : }
411 :
412 : // 参数有效性检查
413 3 : if (src.size() == 0) {
414 0 : HCCL_INFO("%s src memory size is 0, not need copy.", __func__);
415 0 : return HCCL_SUCCESS;
416 : }
417 :
418 3 : if (src == dst) {
419 3 : HCCL_INFO("%s src memory and dst memory is same, not need copy.", __func__);
420 3 : return HCCL_SUCCESS;
421 : }
422 :
423 0 : if (dst.size() < src.size()) {
424 0 : HCCL_ERROR(
425 : "%s The size of dst is smaller than that of src. dst addr[%p], dst size[%llu], "
426 : "src addr[%p], src size[%llu]",
427 : __func__, dst.ptr(), dst.size(), src.ptr(), src.size());
428 0 : return HCCL_E_PTR;
429 : }
430 0 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
431 :
432 : // 将数据按4GB切分循环处理
433 0 : uint64_t spiltLoop = 0;
434 0 : uint64_t addrOffset = 0;
435 0 : uint64_t countSplit = 0;
436 0 : uint64_t countSize = src.size();
437 0 : uint8_t* sqeBuffer = nullptr;
438 0 : uint8_t* sqeTypeAddr = nullptr;
439 0 : uint8_t* sqeDfxInfoAddr = nullptr;
440 0 : uint16_t taskId = 0U;
441 0 : HcclReduceOp redOp = HCCL_REDUCE_RESERVED;
442 0 : aclrtReduceKind rtReduceOp = RK_MAP_TABLE[redOp];
443 :
444 0 : if (countSize > HCCL_SDMA_MAX_COUNT_4GB) {
445 0 : spiltLoop = (countSize % HCCL_SDMA_MAX_COUNT_4GB) ? (countSize / HCCL_SDMA_MAX_COUNT_4GB) :
446 0 : ((countSize / HCCL_SDMA_MAX_COUNT_4GB) - 1);
447 0 : HCCL_INFO(
448 : "%s MemcpyAsync SDMA task countSize is bigger than 4GB"
449 : " and do segmentation splitloop[%llu]",
450 : __func__, spiltLoop);
451 : }
452 0 : uint8_t linkType = static_cast<uint8_t>(inLinkType);
453 0 : for (uint64_t index = 0; index <= spiltLoop; index++) {
454 0 : addrOffset = index * HCCL_SDMA_MAX_COUNT_4GB;
455 0 : countSplit = (index == spiltLoop) ? (countSize - index * HCCL_SDMA_MAX_COUNT_4GB) : (HCCL_SDMA_MAX_COUNT_4GB);
456 0 : void* srcSplit = static_cast<void*>(static_cast<char*>(const_cast<void*>(src.ptr())) + addrOffset);
457 0 : void* dstSplit = static_cast<void*>(static_cast<char*>(dst.ptr()) + addrOffset);
458 :
459 0 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
460 0 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
461 0 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
462 0 : dfxInfo->remoteRank = remoteUserRank;
463 0 : dfxInfo->notifyId = INVALID_VALUE_RANKID;
464 0 : addOneMemcpySqe_(
465 0 : streamInfo.actualStreamId, taskId, srcSplit, countSplit, ACL_FLOAT, rtReduceOp, dstSplit, 0,
466 : aicpuInfo_.ssid, aicpuInfo_.devId, aicpuInfo_.overflowAddr, linkType, sqeBuffer, sqeTypeAddr, hcclQos_);
467 :
468 0 : PLF_CONFIG_INFO(
469 : PLF_TASK,
470 : "%s para: linkType[%u] srcSplit[%p] dstSplit[%p] countSplit[%llu] taskId[%u] streamId[%u] remoteRank[%u]",
471 : __func__, linkType, srcSplit, dstSplit, countSplit, taskId, streamInfo.actualStreamId, remoteUserRank);
472 : }
473 0 : return HCCL_SUCCESS;
474 : }
475 :
476 0 : HcclResult DispatcherAiCpu::ClearLaunchContext()
477 : {
478 0 : HCCL_INFO("[DispatcherAiCpu][ClearLaunchContext] clear launch context");
479 :
480 0 : key_ = OpUnfoldKey();
481 0 : cachePtr_ = nullptr;
482 0 : userInputMemRanges_.clear();
483 0 : userOutputMemRanges_.clear();
484 0 : isAlltoallv_ = false;
485 0 : alltoallvMetadataPtr_ = nullptr;
486 0 : needAddSqe_ = false;
487 :
488 0 : return HCCL_SUCCESS;
489 : }
490 :
491 0 : HcclResult DispatcherAiCpu::SetLaunchContext(
492 : const OpUnfoldKey& key, OpUnfoldCache* cachePtr, const std::vector<OpUnfoldMemRange>& userInputMemRanges,
493 : const std::vector<OpUnfoldMemRange>& userOutputMemRanges, const bool isAlltoallv,
494 : const AlltoallvMetadata* alltoallvMetadataPtr)
495 : {
496 0 : CHK_PTR_NULL(cachePtr);
497 :
498 0 : HCCL_INFO("[DispatcherAiCpu][SetLaunchContext] set launch context for key %s", key.GetKeyString().c_str());
499 :
500 0 : if (isAlltoallv) {
501 0 : CHK_PTR_NULL(alltoallvMetadataPtr);
502 0 : CHK_RET(alltoallvMetadataPtr->Check(false));
503 : }
504 :
505 0 : key_ = key;
506 0 : cachePtr_ = cachePtr;
507 0 : userInputMemRanges_ = userInputMemRanges;
508 0 : userOutputMemRanges_ = userOutputMemRanges;
509 0 : isAlltoallv_ = isAlltoallv;
510 0 : alltoallvMetadataPtr_ = alltoallvMetadataPtr;
511 0 : needAddSqe_ = true;
512 :
513 0 : return HCCL_SUCCESS;
514 : }
515 :
516 0 : HcclResult DispatcherAiCpu::LaunchNewTask(
517 : OpUnfoldCacheEntry* entryPtr, const std::vector<OpUnfoldMemRange>& userInputMemRanges,
518 : const std::vector<OpUnfoldMemRange>& userOutputMemRanges, Stream& mainStream, std::vector<Stream>& slaveStreams,
519 : const bool profL1Enable, const bool isAlltoallv, const AlltoallvMetadata& alltoallvMetadata,
520 : const AlltoallvSendRecvInfo& alltoallvSendRecvInfo)
521 : {
522 : // 校验入参
523 0 : CHK_PTR_NULL(entryPtr);
524 0 : if (isAlltoallv) { // 注意: LaunchNewTask是在缓存命中时调用, 此时无launch context,
525 : // 所以不能直接通过key_.opType来判断是否为alltoallv算子, 需要框架侧传入
526 0 : CHK_RET(alltoallvMetadata.Check(true));
527 0 : CHK_RET(alltoallvSendRecvInfo.Check());
528 : }
529 :
530 : // 准备SQE刷新需要的变量
531 0 : size_t sqeCount = 0;
532 0 : uint8_t* sqeArray = nullptr;
533 0 : uint8_t* sqeTypeArray = nullptr;
534 0 : AicpuDfxInfo* sqeDfxInfoArray = nullptr;
535 0 : Stream* streamPtr = nullptr;
536 0 : std::vector<FlipInfo> flipInfos; // taskid==0且flipnum!=0的SQE索引, 即它们前面需要添加placeholder
537 0 : std::vector<uint64_t> profTimestamps; // 只有当profiling L1 enable时, 才需要记录各SQE的刷新时间
538 :
539 : // 准备placeholder需要的变量
540 : uint8_t placeholderSqe[HCCL_SQE_SIZE]; // placeholder SQE
541 : uint8_t placeholderSqeType; // placeholder SQE type
542 0 : AicpuDfxInfo placeholderSqeDfxInfo; // placeholder DfxInfo
543 0 : placeholderSqeDfxInfo.opRingBufferIdx = opRingBufferIdx_;
544 0 : placeholderSqeDfxInfo.remoteRank = INVALID_VALUE_RANKID;
545 0 : placeholderSqeDfxInfo.notifyId = INVALID_VALUE_RANKID;
546 0 : constexpr uint16_t flipPlaceholderTaskId = 0; // FlipPlaceholder的taskId一定为0
547 :
548 : // 下发多段SQE数组,SQE刷新与下发异步执行
549 0 : size_t sqeArrayCount = 0;
550 0 : CHK_RET(entryPtr->GetSqeArrayCount(sqeArrayCount));
551 0 : HCCL_INFO(
552 : "[DispatcherAiCpu][LaunchNewTask] launch new task for sqeArrayCount[%u] in the cache entry at 0x%016llx",
553 : sqeArrayCount, entryPtr);
554 0 : for (size_t arrayIdx = 0; arrayIdx < sqeArrayCount; ++arrayIdx) {
555 : // 刷新并获得对应信息 (之前下发到RTSQ的SQE正在异步被消费)
556 0 : CHK_RET(entryPtr->UpdateAndGetSqeArray(
557 : arrayIdx, userInputMemRanges, userOutputMemRanges, mainStream, slaveStreams, opRingBufferIdx_, sqeCount,
558 : &sqeArray, &sqeTypeArray, &sqeDfxInfoArray, &streamPtr, flipInfos, profL1Enable, profTimestamps,
559 : isAlltoallv, alltoallvMetadata, alltoallvSendRecvInfo));
560 :
561 : // Profiling timestamp的个数应该等于缓存的SQE个数 + flip placeholder个数
562 0 : CHK_PRT_RET(
563 : (!profL1Enable) && (profTimestamps.size() != 0),
564 : HCCL_ERROR(
565 : "[DispatcherAiCpu][LaunchNewTask] profL1Enable[%u] profTimestamps.size[%u]", profL1Enable,
566 : profTimestamps.size()),
567 : HCCL_E_INTERNAL);
568 0 : CHK_PRT_RET(
569 : profL1Enable && (profTimestamps.size() != (sqeCount + flipInfos.size())),
570 : HCCL_ERROR(
571 : "[DispatcherAiCpu][LaunchNewTask] profL1Enable[%u] profTimestamps.size[%u] sqeCount[%u] "
572 : "flipInfos.size[%u]",
573 : profL1Enable, profTimestamps.size(), sqeCount, flipInfos.size()),
574 : HCCL_E_INTERNAL);
575 :
576 : // 打印缓存并下发的SQE内容for debug
577 : // 设置HCCL_DEBUG_CONFIG="task", 或者设置ASCEND_GLOBAL_LOG_LEVEL=0
578 0 : int32_t streamId = streamPtr->GetHcclStreamInfo().actualStreamId;
579 0 : if ((UNLIKELY(GetExternalInputDebugConfig() & PLF_TASK)) || UNLIKELY(HcclCheckLogLevel(HCCL_LOG_DEBUG))) {
580 0 : PLF_CONFIG_DEBUG(
581 : PLF_TASK,
582 : "[DispatcherAicpu][LaunchNewTask] dump content of %uth cached SQE array with %u cached SQEs and stream "
583 : "id %u",
584 : arrayIdx, sqeCount, streamId);
585 0 : for (size_t sqeIdx = 0; sqeIdx < sqeCount; ++sqeIdx) {
586 0 : uint8_t* sqePtr = sqeArray + sqeIdx * HCCL_SQE_SIZE;
587 0 : const uint8_t sqeType = sqeTypeArray[sqeIdx];
588 0 : PLF_CONFIG_DEBUG(PLF_TASK, "[DispatcherAicpu][LaunchNewTask] %uth cached SQE", sqeIdx);
589 0 : CHK_RET(OpUnfoldCache::DumpSqeContent(sqePtr, sqeType));
590 :
591 0 : const AicpuDfxInfo& dfxinfo = sqeDfxInfoArray[sqeIdx];
592 0 : PLF_CONFIG_DEBUG(
593 : PLF_TASK,
594 : "[DispatcherAicpu][LaunchNewTask] AicpuDfxInfo: remoteRank[%u] opRingBufferIdx[%u] notifyId[%u]",
595 : dfxinfo.remoteRank, dfxinfo.opRingBufferIdx, dfxinfo.notifyId);
596 : }
597 : }
598 :
599 0 : HCCL_INFO("[DispatcherAiCpu][LaunchNewTask] arrayIdx[%u] flipInfos.size[%u]", arrayIdx, flipInfos.size());
600 :
601 : // 分段下发
602 0 : size_t sqeStartIdx = 0; // 要拷贝的SQE在sqeArray中的起始索引
603 0 : size_t profTimestampStartIdx = 0; // 要拷贝的profiling timestamp在profTimestamps中的起始索引
604 0 : for (size_t i = 0; i < flipInfos.size(); ++i) {
605 : // Copy [sqeStartIdx, curZeroTaskidSqeIdx) + placeholder into RTSQ
606 0 : const size_t curZeroTaskidSqeIdx = flipInfos[i].first;
607 0 : const size_t curSqeCount = curZeroTaskidSqeIdx - sqeStartIdx + 1;
608 0 : CHK_PRT_RET(
609 : curZeroTaskidSqeIdx < sqeStartIdx,
610 : HCCL_ERROR(
611 : "[DispatcherAiCpu][LaunchNewTask] curZeroTaskidSqeIdx[%u] < sqeStartIdx[%u]", curZeroTaskidSqeIdx,
612 : sqeStartIdx),
613 : HCCL_E_INTERNAL);
614 :
615 : // Wait RTSQ for curSqeCount SQE (including placeholder) space
616 0 : HCCL_INFO("[DispatcherAiCpu][LaunchNewTask] wait rtsq for %u sqe space", curSqeCount);
617 0 : CHK_RET(WaitRtsq(*streamPtr, curSqeCount, true));
618 :
619 : // 下发sqeArray[sqeStartIdx, curZeroTaskidSqeIdx)到RTSQ中 (excluding placeholder)
620 0 : if (curZeroTaskidSqeIdx > sqeStartIdx) { // 需要下发的cached SQE数量 > 0
621 0 : HCCL_INFO(
622 : "[DispatcherAiCpu][LaunchNewTask] launch %uth sqeArray[%u:%u)", arrayIdx, sqeStartIdx,
623 : curZeroTaskidSqeIdx);
624 0 : CHK_RET(MemcpyRtsq(
625 : *streamPtr, curSqeCount - 1, sqeArray + sqeStartIdx * HCCL_SQE_SIZE, sqeTypeArray + sqeStartIdx,
626 : sqeDfxInfoArray + sqeStartIdx, profL1Enable, profTimestamps, profTimestampStartIdx));
627 0 : if (profL1Enable) {
628 0 : profTimestampStartIdx += (curSqeCount - 1); // Cached SQEs
629 : }
630 : }
631 :
632 : // 根据具体SQE下发信息更新placeholder
633 : // 参考AddFlipTask, 设置placeholder SQE (streamId和stream相关, flipNum和SQE下发相关)
634 : // 注意: 由于flipPlaceholder DfxInfo在当前算子下不变, 提前设置, 后续只需要刷新placeholder即可
635 0 : const uint16_t curFlipNum = flipInfos[i].second;
636 0 : CHK_PRT_RET(
637 : curFlipNum == 0,
638 : HCCL_ERROR(
639 : "[DispatcherAiCpu][LaunchNewTask] invalid flipNum[%u]: flipInfoIdx[%u] arrayIdx[%u] "
640 : "zeroTaskidSqeIdx[%u] streamId[%u]",
641 : curFlipNum, i, arrayIdx, curZeroTaskidSqeIdx, streamId),
642 : HCCL_E_INTERNAL);
643 0 : CHK_PTR_NULL(addOneFlipPlaceHolderSqe_);
644 0 : addOneFlipPlaceHolderSqe_(streamId, curFlipNum, flipPlaceholderTaskId, placeholderSqe, &placeholderSqeType);
645 0 : HCCL_INFO(
646 : "[DispatcherAiCpu][LaunchNewTask] flip placeholder SQE with flipnum[%u] and streamid[%u]", curFlipNum,
647 : streamId);
648 :
649 : // 下发placeholder SQE
650 0 : HCCL_INFO(
651 : "[DispatcherAiCpu][LaunchNewTask] launch placeholder SQE after %uth sqeArray[%u:%u)", arrayIdx,
652 : sqeStartIdx, curZeroTaskidSqeIdx);
653 0 : CHK_RET(MemcpyRtsq(
654 : *streamPtr, 1, placeholderSqe, &placeholderSqeType, &placeholderSqeDfxInfo, profL1Enable,
655 : profTimestamps, profTimestampStartIdx));
656 0 : if (profL1Enable) {
657 0 : profTimestampStartIdx += 1; // Flip placeholder
658 : }
659 :
660 0 : sqeStartIdx = curZeroTaskidSqeIdx;
661 : }
662 :
663 : // 按需下发剩余SQE
664 0 : if (sqeStartIdx < sqeCount) {
665 : // Copy [sqeStartIdx, sqeCount - 1] into RTSQ
666 0 : const size_t remainSqeCount = sqeCount - sqeStartIdx;
667 :
668 : // Wait RTSQ for remainSqeCount SQE space
669 0 : HCCL_INFO("[DispatcherAiCpu][LaunchNewTask] wait rtsq for %u sqe space", remainSqeCount);
670 0 : CHK_RET(WaitRtsq(*streamPtr, remainSqeCount, true));
671 :
672 : // 下发sqeArray[sqeStartIdx, sqeCount - 1]到RTSQ中
673 0 : HCCL_INFO(
674 : "[DispatcherAiCpu][LaunchNewTask] launch %uth sqeArray[%u:%u]", arrayIdx, sqeStartIdx, sqeCount - 1);
675 0 : CHK_RET(MemcpyRtsq(
676 : *streamPtr, remainSqeCount, sqeArray + sqeStartIdx * HCCL_SQE_SIZE, sqeTypeArray + sqeStartIdx,
677 : sqeDfxInfoArray + sqeStartIdx, profL1Enable, profTimestamps, profTimestampStartIdx));
678 0 : if (profL1Enable) {
679 0 : profTimestampStartIdx += remainSqeCount; // Remaining cached SQEs
680 : }
681 : }
682 :
683 : // 为下一段SQE数组的刷新清理变量
684 0 : sqeCount = 0;
685 0 : sqeArray = nullptr;
686 0 : sqeTypeArray = nullptr;
687 0 : sqeDfxInfoArray = nullptr;
688 0 : streamPtr = nullptr;
689 0 : flipInfos.clear();
690 : }
691 :
692 : // 下发完当前cache entry中所有SQE数组后, 更新input/output memory ranges, 与SQE中in-place update的addr-related
693 : // fields保持一直
694 0 : CHK_RET(entryPtr->SetInputOutputMemRanges(userInputMemRanges, userOutputMemRanges));
695 :
696 0 : return HCCL_SUCCESS;
697 0 : }
698 :
699 11 : HcclResult DispatcherAiCpu::LaunchTask(Stream& stream, bool isBlockLaunch)
700 : {
701 11 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
702 11 : HcclSqeContext* sqeContext = stream.GetSqeContextPtr();
703 11 : CHK_PTR_NULL(sqeContext);
704 11 : SqeRingBuffer* sqeContextBuffer = &(sqeContext->buffer);
705 11 : CHK_PTR_NULL(sqeContextBuffer);
706 11 : const auto cnt = sqeContextBuffer->sqeCnt;
707 11 : if (cnt == 0) {
708 6 : CHK_PRT_CONT(
709 : isBlockLaunch, HCCL_DEBUG("no sqe, streamId:%d, sqId:%u", streamInfo.actualStreamId, streamInfo.sqId));
710 6 : return HCCL_SUCCESS;
711 5 : } else if (cnt > streamInfo.sqDepth) {
712 1 : HCCL_ERROR("LaunchTask fail, cnt:%u should be less than sqDepth:%u", cnt, streamInfo.sqDepth);
713 1 : return HCCL_E_PTR;
714 : }
715 :
716 4 : auto& head = sqeContextBuffer->sqHead;
717 4 : auto& tail = sqeContextBuffer->sqTail;
718 4 : u32 newTail = (tail + cnt) % streamInfo.sqDepth;
719 : // 仅在阻塞下发场景打印,避免非阻塞场景调用时刷屏
720 4 : CHK_PRT_CONT(
721 : isBlockLaunch,
722 : HCCL_INFO(
723 : "Before send sqid:%d cnt:%u head:%u curtail:%u newTail:%u", streamInfo.sqId, cnt, head, tail, newTail));
724 :
725 4 : u64 startUsec = GetCurAicpuTimestamp();
726 4 : u64 lastUsec = startUsec;
727 2951612 : while (((tail < head ? streamInfo.sqDepth : 0U) + tail - head + cnt >= streamInfo.sqDepth)
728 2951612 : && (tail != head)) { // 判断剩余sqe空间是否足够下发
729 : // 需要放在while循环进来后第一个执行
730 2951610 : CHK_RET(QuerySqStatusByType(aicpuInfo_.devId, streamInfo.sqId, DRV_SQCQ_PROP_SQ_HEAD, head));
731 :
732 : // 非阻塞下发场景,rtsq队列空间不足时直接返回
733 2951610 : if (isBlockLaunch == false) {
734 0 : return HCCL_SUCCESS;
735 : }
736 :
737 : // 当前流无法下发,把其他流都launch一遍,避免等待的其他流没有launch
738 4483951 : for (auto it = streamMap_.begin(); it != streamMap_.end(); ++it) {
739 1532341 : if (it->first != streamInfo.actualStreamId) {
740 1 : if (it->second.IsInvalid()) { // 跳过已销毁的stream (streamMap_只增不删, 原stream销毁后副本通过shared
741 : // invalid标志感知)
742 0 : HCCL_WARNING(
743 : "[DispatcherAiCpu][LaunchTask] skip invalid stream in streamMap, streamId:%d", it->first);
744 0 : continue;
745 : }
746 1 : CHK_RET(LaunchTask(it->second, false));
747 : }
748 : }
749 2951610 : u64 curUsec = GetCurAicpuTimestamp();
750 2951610 : if (dfxTimeOutConfig_.sqFullWaitTimeOut != 0
751 2951609 : && (curUsec - startUsec > NANOSECOND_TO_SECOND * dfxTimeOutConfig_.sqFullWaitTimeOut)) {
752 2 : HCCL_ERROR(
753 : "Rtsq full, timeout %lus. curhead:%u, sqId:%d", dfxTimeOutConfig_.sqFullWaitTimeOut, head,
754 : streamInfo.sqId);
755 2 : return HCCL_E_AGAIN;
756 : }
757 :
758 : // 等待下发阶段,每隔30s打印一次状态
759 2951608 : if (curUsec - lastUsec > NANOSECOND_TO_SECOND * dfx::kPrintSqInterval) {
760 0 : lastUsec = curUsec;
761 0 : HCCL_RUN_INFO(
762 : "[LaunchTask][WaitLaunchWhileLoop]Current state. sqid:%d, head:%u, tail:%u, cnt:%u", streamInfo.sqId,
763 : head, tail, cnt);
764 : }
765 :
766 : // 下发过程中出现cqe异常
767 2951608 : if (checkOpExecStatusCallback_ != nullptr) {
768 0 : HcclResult opExecStatus = checkOpExecStatusCallback_();
769 0 : CHK_PRT_RET(
770 : opExecStatus != HCCL_SUCCESS,
771 : HCCL_ERROR("hccl aicpu stop launch for task exception or stop command, ret:%d", opExecStatus),
772 : opExecStatus);
773 : }
774 : }
775 :
776 2 : uint32_t left = streamInfo.sqDepth - tail; // sqeAddr 剩余空间
777 2 : const auto tailSqeIdx = sqeContextBuffer->tailSqeIdx;
778 2 : HCCL_INFO("cpy sqe, left:%u, tailSqeId:%u, cnt:%u, streamId:%u", left, tailSqeIdx, cnt, stream.id());
779 2 : if (cnt <= left) { // 剩余buffer放得下新增sqe
780 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
781 : reinterpret_cast<uint8_t*>(streamInfo.sqBaseAddr) + tail * HCCL_SQE_SIZE, left * HCCL_SQE_SIZE,
782 : sqeContextBuffer->localBuff + (tailSqeIdx - cnt) * HCCL_SQE_SIZE, cnt * HCCL_SQE_SIZE));
783 :
784 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
785 : sqeContextBuffer->rtsMirrorBuffer + tail * HCCL_SQE_SIZE, left * HCCL_SQE_SIZE,
786 : sqeContextBuffer->localBuff + (tailSqeIdx - cnt) * HCCL_SQE_SIZE, cnt * HCCL_SQE_SIZE));
787 :
788 1 : CHK_SAFETY_FUNC_RET(
789 : memcpy_s(sqeContextBuffer->rtsqSqeType + tail, left, sqeContextBuffer->sqeType + (tailSqeIdx - cnt), cnt));
790 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
791 : sqeContextBuffer->rtsDfxInfo + tail, left * sizeof(AicpuDfxInfo),
792 : sqeContextBuffer->dfxInfo + (tailSqeIdx - cnt), cnt * sizeof(AicpuDfxInfo)));
793 : } else {
794 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
795 : reinterpret_cast<uint8_t*>(streamInfo.sqBaseAddr) + tail * HCCL_SQE_SIZE, left * HCCL_SQE_SIZE,
796 : sqeContextBuffer->localBuff + (tailSqeIdx - cnt) * HCCL_SQE_SIZE, left * HCCL_SQE_SIZE));
797 :
798 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
799 : reinterpret_cast<uint8_t*>(streamInfo.sqBaseAddr), streamInfo.sqDepth * HCCL_SQE_SIZE,
800 : sqeContextBuffer->localBuff + (tailSqeIdx - cnt + left) * HCCL_SQE_SIZE, (cnt - left) * HCCL_SQE_SIZE));
801 :
802 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
803 : sqeContextBuffer->rtsMirrorBuffer + tail * HCCL_SQE_SIZE, left * HCCL_SQE_SIZE,
804 : sqeContextBuffer->localBuff + (tailSqeIdx - cnt) * HCCL_SQE_SIZE, left * HCCL_SQE_SIZE));
805 :
806 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
807 : sqeContextBuffer->rtsMirrorBuffer, streamInfo.sqDepth * HCCL_SQE_SIZE,
808 : sqeContextBuffer->localBuff + (tailSqeIdx - cnt + left) * HCCL_SQE_SIZE, (cnt - left) * HCCL_SQE_SIZE));
809 :
810 1 : CHK_SAFETY_FUNC_RET(
811 : memcpy_s(sqeContextBuffer->rtsqSqeType + tail, left, sqeContextBuffer->sqeType + (tailSqeIdx - cnt), left));
812 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
813 : sqeContextBuffer->rtsqSqeType + 0, streamInfo.sqDepth,
814 : sqeContextBuffer->sqeType + (tailSqeIdx - cnt + left), (cnt - left)));
815 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
816 : sqeContextBuffer->rtsDfxInfo + tail, left * sizeof(AicpuDfxInfo),
817 : sqeContextBuffer->dfxInfo + (tailSqeIdx - cnt), left * sizeof(AicpuDfxInfo)));
818 1 : CHK_SAFETY_FUNC_RET(memcpy_s(
819 : sqeContextBuffer->rtsDfxInfo + 0, streamInfo.sqDepth * sizeof(AicpuDfxInfo),
820 : sqeContextBuffer->dfxInfo + (tailSqeIdx - cnt + left), (cnt - left) * sizeof(AicpuDfxInfo)));
821 : }
822 : // 打印算子展开下发的SQE内容for debug
823 : // 设置HCCL_DEBUG_CONFIG="task", 或者设置ASCEND_GLOBAL_LOG_LEVEL=0
824 2 : if ((UNLIKELY(GetExternalInputDebugConfig() & PLF_TASK)) || UNLIKELY(HcclCheckLogLevel(HCCL_LOG_DEBUG))) {
825 2 : const int32_t streamId = stream.GetHcclStreamInfo().actualStreamId;
826 2 : PLF_CONFIG_DEBUG(
827 : PLF_TASK, "[DispatcherAicpu][LaunchTask] dump content of %u dispatched SQEs with stream id %u", cnt,
828 : streamId);
829 :
830 2 : uint8_t* sqeArray = sqeContextBuffer->localBuff + (tailSqeIdx - cnt) * HCCL_SQE_SIZE;
831 2 : uint8_t* sqeTypeArray = sqeContextBuffer->sqeType + (tailSqeIdx - cnt);
832 2 : AicpuDfxInfo* sqeDfxInfoArray = sqeContextBuffer->dfxInfo + (tailSqeIdx - cnt);
833 14 : for (size_t sqeIdx = 0; sqeIdx < cnt; ++sqeIdx) {
834 12 : uint8_t* sqePtr = sqeArray + sqeIdx * HCCL_SQE_SIZE;
835 12 : const uint8_t sqeType = sqeTypeArray[sqeIdx];
836 12 : if (sqeType == SqeType::FLIP_PLACEHOLDER_SQE) {
837 0 : const rtStarsPlaceHolderSqe_t* placeholderSqePtr
838 0 : = reinterpret_cast<const rtStarsPlaceHolderSqe_t*>(sqeArray + sqeIdx * HCCL_SQE_SIZE);
839 0 : PLF_CONFIG_DEBUG(
840 : PLF_TASK,
841 : "[DispatcherAicpu][LaunchTask] %uth dispatched SQE (placeholder) header.type[%u] taskid[%u]",
842 : sqeIdx, placeholderSqePtr->header.type, placeholderSqePtr->header.taskId);
843 : } else {
844 12 : PLF_CONFIG_DEBUG(PLF_TASK, "[DispatcherAicpu][LaunchTask] %uth dispatched SQE", sqeIdx);
845 : }
846 :
847 12 : CHK_RET(OpUnfoldCache::DumpSqeContent(sqePtr, sqeType));
848 :
849 12 : const AicpuDfxInfo& dfxinfo = sqeDfxInfoArray[sqeIdx];
850 12 : PLF_CONFIG_DEBUG(
851 : PLF_TASK, "[DispatcherAicpu][LaunchTask] AicpuDfxInfo: remoteRank[%u] opRingBufferIdx[%u] notifyId[%u]",
852 : dfxinfo.remoteRank, dfxinfo.opRingBufferIdx, dfxinfo.notifyId);
853 : }
854 : }
855 :
856 : // 当前算子展开的SQE需要被动态缓存
857 2 : if (needAddSqe_) {
858 0 : CHK_PTR_NULL(cachePtr_);
859 :
860 : // 查找key对应的cache entry, 如果不存在 (即当前算子第一次LaunchTask), 创建新的cache entry
861 0 : OpUnfoldCacheEntry* entryPtr = nullptr;
862 0 : CHK_RET(cachePtr_->FindEntry(key_, &entryPtr));
863 0 : if (entryPtr == nullptr) {
864 0 : CHK_RET(cachePtr_->AddEntry(key_, userInputMemRanges_, userOutputMemRanges_, &entryPtr));
865 : }
866 0 : CHK_PTR_NULL(entryPtr);
867 :
868 : // 准备SQE相关信息的数组基地址
869 0 : uint8_t* sqeArray = sqeContextBuffer->localBuff + (tailSqeIdx - cnt) * HCCL_SQE_SIZE;
870 0 : uint8_t* sqeTypeArray = sqeContextBuffer->sqeType + (tailSqeIdx - cnt);
871 0 : AicpuDfxInfo* sqeDfxInfoArray = sqeContextBuffer->dfxInfo + (tailSqeIdx - cnt);
872 :
873 : // 遍历sqeType找到placeholder的位置
874 0 : std::vector<size_t> placeholderIdxes;
875 0 : uint8_t* curSqeTypePtr = sqeTypeArray;
876 0 : for (size_t sqeTypeIdx = 0; sqeTypeIdx < cnt; ++sqeTypeIdx) {
877 0 : if (*curSqeTypePtr == SqeType::FLIP_PLACEHOLDER_SQE) {
878 0 : placeholderIdxes.emplace_back(sqeTypeIdx);
879 : }
880 0 : ++curSqeTypePtr;
881 : }
882 :
883 : // 在动态缓存中分配实际需要的SQE数组
884 0 : const size_t cacheableSqeCount = cnt - placeholderIdxes.size();
885 0 : const int32_t streamId = stream.GetHcclStreamInfo().actualStreamId;
886 0 : size_t arrayIdx = 0;
887 0 : CHK_RET(entryPtr->AllocSqeArray(cacheableSqeCount, streamId, arrayIdx));
888 :
889 : // 分段拷贝SQE相关信息到cache entry中
890 0 : size_t cacheableSqeStartIdx = 0; // SQE start index (在动态缓存对应SQE数组中的索引)
891 0 : size_t bufferSqeStartIdx = 0; // SQE start index (在SQE ring buffer中的索引)
892 0 : for (size_t i = 0; i < placeholderIdxes.size(); ++i) {
893 : // [bufferSqeStartIdx, curPlaceholderIdx) -> [cacheableSqeStartIdx, cacheableSqeStartIdx + curPlaceholderIdx
894 : // - bufferSqeStartIdx)
895 0 : const size_t curPlaceholderIdx = placeholderIdxes[i];
896 0 : HCCL_INFO(
897 : "[DispatcherAicpu][LaunchTask] %uth placeholder copy dispatchedSqeArray[%u:%u) into "
898 : "cachedSqeArrays[%u][%u:%u)",
899 : i, bufferSqeStartIdx, curPlaceholderIdx, arrayIdx, cacheableSqeStartIdx,
900 : cacheableSqeStartIdx + curPlaceholderIdx - bufferSqeStartIdx);
901 0 : if (curPlaceholderIdx <= bufferSqeStartIdx) { // NO non-placeholder dispatched SQE to admit
902 : // NOTE: NO need to change cacheableSqeStartIdx
903 0 : bufferSqeStartIdx = curPlaceholderIdx + 1;
904 : } else {
905 0 : const size_t curSqeCount = curPlaceholderIdx - bufferSqeStartIdx;
906 0 : CHK_RET(entryPtr->MemcpySqeArray(
907 : arrayIdx, cacheableSqeStartIdx, curSqeCount, sqeArray + bufferSqeStartIdx * HCCL_SQE_SIZE,
908 : sqeTypeArray + bufferSqeStartIdx, sqeDfxInfoArray + bufferSqeStartIdx, isAlltoallv_,
909 : alltoallvMetadataPtr_));
910 0 : cacheableSqeStartIdx += curSqeCount;
911 0 : bufferSqeStartIdx = curPlaceholderIdx + 1;
912 : }
913 : }
914 :
915 : // 存在剩余SQE, 即最后一个SQE不是placeholder
916 0 : if (LIKELY(bufferSqeStartIdx < cnt)) {
917 : // [bufferSqeStartIdx, cnt - 1] -> [cacheableSqeStartIdx, cacheableSqeStartIdx + cnt - bufferSqeStartIdx)
918 0 : const size_t curSqeCount = cnt - bufferSqeStartIdx;
919 0 : CHK_RET(entryPtr->MemcpySqeArray(
920 : arrayIdx, cacheableSqeStartIdx, curSqeCount, sqeArray + bufferSqeStartIdx * HCCL_SQE_SIZE,
921 : sqeTypeArray + bufferSqeStartIdx, sqeDfxInfoArray + bufferSqeStartIdx, isAlltoallv_,
922 : alltoallvMetadataPtr_));
923 : }
924 0 : }
925 :
926 2 : CHK_RET(ConfigSqStatusByType(aicpuInfo_.devId, streamInfo.sqId, DRV_SQCQ_PROP_SQ_TAIL, newTail));
927 2 : tail = newTail;
928 2 : PLF_CONFIG_INFO(
929 : PLF_TASK, "%s success, sqid:%d, sqe_num:%u, curHead:%u, curtail:%u", __func__, streamInfo.sqId, cnt, head,
930 : tail);
931 2 : sqeContextBuffer->sqeCnt = 0;
932 2 : return HCCL_SUCCESS;
933 : }
934 :
935 8 : HcclResult DispatcherAiCpu::LaunchTasksEx(hccl::Stream& stream, std::vector<Stream>& subStreams)
936 : {
937 : /* 两阶段模式,主流待正式执行时再下 */
938 : /* 一阶段第一次,可以先下主流 */
939 8 : HcclResult ret = LaunchTask(stream, true);
940 8 : if (ret != HCCL_SUCCESS) {
941 0 : HCCL_ERROR(
942 : "[DispatcherAiCpu][LaunchTasksEx] "
943 : "launch task failed, sqid:%u, ret:%u",
944 : stream.sqId(), ret);
945 0 : return ret;
946 : }
947 :
948 8 : for (u32 index = 0; index < subStreams.size(); index++) {
949 0 : ret = LaunchTask(subStreams[index], true);
950 0 : if (ret != HCCL_SUCCESS) {
951 0 : HCCL_ERROR(
952 : "[DispatcherAiCpu][LaunchTasksEx] "
953 : "launch task failed, sqid:%u, ret:%u",
954 : subStreams[index].sqId(), ret);
955 0 : return ret;
956 : }
957 : }
958 :
959 8 : return HCCL_SUCCESS;
960 : }
961 :
962 3 : HcclResult DispatcherAiCpu::LaunchAllTasks()
963 : {
964 5 : for (auto it = streamMap_.begin(); it != streamMap_.end(); ++it) {
965 6 : if (it->second
966 3 : .IsInvalid()) { // 跳过已销毁的stream (streamMap_只增不删, 原stream销毁后副本通过shared invalid标志感知)
967 0 : HCCL_WARNING("[DispatcherAiCpu][LaunchAllTasks] skip invalid stream in streamMap, streamId:%d", it->first);
968 0 : continue;
969 : }
970 3 : HcclResult ret = LaunchTask(it->second, true);
971 3 : if (ret != HCCL_SUCCESS) {
972 1 : HCCL_ERROR("DispatcherAiCpu][LaunchAllTasks] launch task failed, sqid:%u, ret:%u", it->second.sqId(), ret);
973 1 : return ret;
974 : }
975 : }
976 2 : return HCCL_SUCCESS;
977 : }
978 :
979 1 : HcclResult DispatcherAiCpu::ReduceAsync(
980 : const void* src, void* dst, u64 dataCount, const HcclDataType datatype, HcclReduceOp redOp, Stream& stream,
981 : HcclReduceType reduceType)
982 : {
983 1 : return (reduceType == HcclReduceType::HCCL_INLINE_REDUCE) ?
984 1 : InlineReduceAsync(src, dataCount, datatype, redOp, stream, dst) :
985 1 : TbeReduceAsync(src, dst, dataCount, datatype, redOp, stream, dst);
986 : }
987 :
988 2 : HcclResult DispatcherAiCpu::InlineReduceAsync(
989 : const void* src, u64 dataCount, const HcclDataType datatype, HcclReduceOp redOp, hccl::Stream& stream, void* dst,
990 : u32 remoteUserRank, hccl::LinkType inLinkType)
991 : {
992 : // 参数有效性检查
993 2 : CHK_PTR_NULL(stream.ptr());
994 2 : if (dataCount == 0) {
995 0 : HCCL_INFO("%s src memory size is 0, not need inline reduce.", __func__);
996 0 : return HCCL_SUCCESS;
997 : }
998 2 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
999 :
1000 2 : aclDataType runtimeDataType = DT_MAP_TABLE[datatype];
1001 2 : aclrtReduceKind rtReduceOp = RK_MAP_TABLE[redOp];
1002 :
1003 : // 将数据按4GB切分循环处理
1004 2 : uint64_t spiltLoop = 0;
1005 2 : uint64_t addr_offset = 0;
1006 2 : uint64_t countSplit = 0;
1007 2 : uint64_t countSize = dataCount * SIZE_TABLE[datatype];
1008 2 : uint8_t* sqeBuffer = nullptr;
1009 2 : uint8_t* sqeTypeAddr = nullptr;
1010 2 : uint8_t* sqeDfxInfoAddr = nullptr;
1011 2 : uint16_t taskId = 0U;
1012 :
1013 2 : if (countSize > HCCL_SDMA_MAX_COUNT_4GB) {
1014 0 : spiltLoop = (countSize % HCCL_SDMA_MAX_COUNT_4GB) ? (countSize / HCCL_SDMA_MAX_COUNT_4GB) :
1015 0 : ((countSize / HCCL_SDMA_MAX_COUNT_4GB) - 1);
1016 0 : HCCL_INFO(
1017 : "%s InlineReduceAsync SDMA task countSize is bigger than 4GB"
1018 : " and do segmentation splitloop:%llu",
1019 : __func__, spiltLoop);
1020 : }
1021 2 : uint8_t linkType = static_cast<uint8_t>(inLinkType);
1022 4 : for (uint64_t index = 0; index <= spiltLoop; index++) {
1023 2 : addr_offset = index * HCCL_SDMA_MAX_COUNT_4GB;
1024 2 : countSplit = (index == spiltLoop) ? (countSize - index * HCCL_SDMA_MAX_COUNT_4GB) : (HCCL_SDMA_MAX_COUNT_4GB);
1025 2 : void* srcSplit = static_cast<void*>(static_cast<char*>(const_cast<void*>(src)) + addr_offset);
1026 2 : void* dstSplit = static_cast<void*>(static_cast<char*>(dst) + addr_offset);
1027 :
1028 2 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
1029 2 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
1030 2 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
1031 2 : dfxInfo->remoteRank = remoteUserRank;
1032 2 : dfxInfo->notifyId = INVALID_VALUE_RANKID;
1033 2 : addOneMemcpySqe_(
1034 2 : streamInfo.actualStreamId, taskId, srcSplit, countSplit, runtimeDataType, rtReduceOp, dstSplit, 0,
1035 : aicpuInfo_.ssid, aicpuInfo_.devId, aicpuInfo_.overflowAddr, linkType, sqeBuffer, sqeTypeAddr, hcclQos_);
1036 :
1037 2 : PLF_CONFIG_INFO(
1038 : PLF_TASK,
1039 : "%s para: linkType[%u] srcSplit[%p] dstSplit[%p] countSplit[%llu] taskId[%u] streamId[%u] remoteRank[%u] "
1040 : "rtDatatType[%d] rtReduceOp[%d]",
1041 : __func__, linkType, srcSplit, dstSplit, countSplit, taskId, streamInfo.actualStreamId, remoteUserRank,
1042 : runtimeDataType, rtReduceOp);
1043 : }
1044 :
1045 2 : return HCCL_SUCCESS;
1046 : }
1047 :
1048 1 : HcclResult DispatcherAiCpu::TbeReduceAsync(
1049 : [[maybe_unused]] const void* src1, [[maybe_unused]] const void* src2, [[maybe_unused]] u64 count,
1050 : [[maybe_unused]] const HcclDataType datatype, [[maybe_unused]] HcclReduceOp redOp, [[maybe_unused]] Stream& stream,
1051 : [[maybe_unused]] const void* dst)
1052 : {
1053 1 : HCCL_ERROR("[DispatcherAiCpu][TbeReduceAsync] aicpu do not support the tbe reduce");
1054 1 : return HCCL_E_NOT_SUPPORT;
1055 : }
1056 :
1057 5 : HcclResult DispatcherAiCpu::RdmaSend(u32 dbindex, u64 dbinfo, hccl::Stream& stream, RdmaTaskInfo& taskInfo)
1058 : {
1059 5 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
1060 :
1061 5 : uint8_t* sqeBuffer = nullptr;
1062 5 : uint8_t* sqeTypeAddr = nullptr;
1063 5 : uint8_t* sqeDfxInfoAddr = nullptr;
1064 5 : uint16_t taskId = 0U;
1065 :
1066 5 : CHK_RET(GetStreamSqeBufferAddr(stream, sqeBuffer, sqeTypeAddr, sqeDfxInfoAddr, taskId));
1067 5 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
1068 5 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
1069 5 : dfxInfo->remoteRank = taskInfo.remoteRank;
1070 5 : dfxInfo->notifyId = INVALID_UINT; // 多个wr只敲一次doorbell的情况下,一般只会有一个notify
1071 :
1072 5 : uint32_t wrLen = 0; // 统计wr的总数据量
1073 5 : for (const WrInformation& wr : taskInfo.wrInfos) {
1074 0 : wrLen += wr.wrData.memList.len;
1075 0 : dfxInfo->notifyId = (wr.notifyId != INVALID_UINT) ? wr.notifyId : dfxInfo->notifyId;
1076 : }
1077 :
1078 5 : u64 dbAddr = CalcDbAddr(dbindex);
1079 5 : addOneRdmaDbSendSqe_(
1080 5 : streamInfo.actualStreamId, taskId, dbinfo, dbAddr, wrLen, static_cast<uint8_t>(taskInfo.rdmaType), sqeBuffer,
1081 : sqeTypeAddr);
1082 :
1083 5 : PLF_CONFIG_INFO(
1084 : PLF_TASK, "%s para: streamId[%u] taskId[%u] remoteRank[%u] RdmaType[%d] wrLen[%u] notifyId[%u]", __func__,
1085 : streamInfo.actualStreamId, taskId, taskInfo.remoteRank, taskInfo.rdmaType, wrLen, dfxInfo->notifyId);
1086 :
1087 5 : return HCCL_SUCCESS;
1088 : }
1089 :
1090 0 : HcclResult DispatcherAiCpu::RdmaRecord(
1091 : [[maybe_unused]] u32 dbindex, [[maybe_unused]] u64 dbinfo, [[maybe_unused]] const struct SendWr& wr,
1092 : [[maybe_unused]] hccl::Stream& stream, [[maybe_unused]] RdmaType rdmaType, [[maybe_unused]] u32 userRank,
1093 : [[maybe_unused]] u64 offset, [[maybe_unused]] u32 notifyId)
1094 : {
1095 0 : return HCCL_SUCCESS;
1096 : }
1097 :
1098 13 : HcclResult DispatcherAiCpu::GetStreamSqeBufferAddr(
1099 : hccl::Stream& stream, uint8_t*& sqeBufferAddr, uint8_t*& sqeTypeAddr, uint8_t*& sqeDfxInfoAddr, uint16_t& taskId)
1100 : {
1101 13 : SaveStreamInfo(stream);
1102 13 : HcclSqeContext* sqeContext = stream.GetSqeContextPtr();
1103 13 : CHK_PTR_NULL(sqeContext);
1104 13 : if (UNLIKELY(sqeContext->buffer.sqeCnt >= HCCL_PER_LAUNCH_SQE_CNT)) {
1105 0 : HCCL_INFO("GetStreamSqeBufferAddr tailSqeIdx[%u], try to launchTask", sqeContext->buffer.tailSqeIdx);
1106 0 : CHK_RET(LaunchTask(stream, true));
1107 : }
1108 13 : if (UNLIKELY(sqeContext->buffer.tailSqeIdx >= HCCL_SQE_MAX_CNT)) {
1109 0 : CHK_RET(LaunchTask(stream, true));
1110 :
1111 0 : if (callback_ != nullptr) {
1112 0 : hccl::AiCPUStreamTasks para(stream.id(), reinterpret_cast<void*>(sqeContext));
1113 0 : hccl::TaskPara taskPara(TaskType::TASK_BATCH_REPORT, para);
1114 0 : callback_(callBackUserPtr_, (void*)&taskPara, sizeof(struct TaskPara));
1115 0 : }
1116 : }
1117 13 : SqeRingBuffer* sqeContextBuffer = &(sqeContext->buffer);
1118 13 : uint16_t flipNum = sqeContextBuffer->filpNum;
1119 13 : uint16_t nextTaskId = sqeContextBuffer->tailSqeTaskId;
1120 : // nextTaskId=0的时候下发PlaceHolder
1121 13 : if (UNLIKELY(nextTaskId == 0 && flipNum != 0)) {
1122 0 : CHK_RET(AddFlipTask(stream));
1123 : }
1124 13 : if (UNLIKELY(sqeContext->buffer.tailSqeIdx >= HCCL_SQE_MAX_CNT)) {
1125 0 : CHK_RET(LaunchTask(stream, true));
1126 :
1127 0 : if (callback_ != nullptr) {
1128 0 : hccl::AiCPUStreamTasks para(stream.id(), reinterpret_cast<void*>(sqeContext));
1129 0 : hccl::TaskPara taskPara(TaskType::TASK_BATCH_REPORT, para);
1130 0 : callback_(callBackUserPtr_, (void*)&taskPara, sizeof(struct TaskPara));
1131 0 : }
1132 : }
1133 13 : CHK_RET(stream.GetNextSqeBufferAddr(sqeBufferAddr, sqeTypeAddr, sqeDfxInfoAddr, taskId));
1134 13 : return HCCL_SUCCESS;
1135 : }
1136 :
1137 2 : HcclResult DispatcherAiCpu::WaitRtsq(Stream& stream, const size_t& sqeCount, const bool isBlockLaunch)
1138 : {
1139 : // 注意: 目前WaitRtsq不会被递归调用, 所以isBlockLaunch永远为true; 为防止以后LaunchTask递归使用WaitRtsq,
1140 : // 编码时考虑isBlockLaunch为false的情况
1141 :
1142 : // 检验入参
1143 2 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
1144 2 : if (sqeCount == 0) {
1145 0 : CHK_PRT_CONT(
1146 : isBlockLaunch, HCCL_DEBUG(
1147 : "[DispatcherAiCpu][WaitRtsq] no sqe, streamId:%d, sqId:%u", streamInfo.actualStreamId,
1148 : streamInfo.sqId));
1149 0 : return HCCL_SUCCESS;
1150 2 : } else if (sqeCount > streamInfo.sqDepth) {
1151 0 : HCCL_ERROR(
1152 : "[DispatcherAiCpu][WaitRtsq] sqeCount %u should be smaller than sqDepth %u]", sqeCount, streamInfo.sqDepth);
1153 0 : return HCCL_E_PTR;
1154 : }
1155 :
1156 : // Get head and tail of RTSQ ring buffer
1157 2 : HcclSqeContext* sqeContext = stream.GetSqeContextPtr();
1158 2 : CHK_PTR_NULL(sqeContext);
1159 2 : SqeRingBuffer* sqeContextBuffer = &(sqeContext->buffer);
1160 2 : CHK_PTR_NULL(sqeContextBuffer);
1161 2 : uint32_t& head = sqeContextBuffer->sqHead;
1162 2 : uint32_t& tail = sqeContextBuffer->sqTail;
1163 :
1164 : // Dump debug information
1165 2 : const uint32_t newTail = (tail + sqeCount) % streamInfo.sqDepth;
1166 : // 仅在阻塞下发场景打印,避免非阻塞场景调用时刷屏
1167 2 : CHK_PRT_CONT(
1168 : isBlockLaunch, HCCL_INFO(
1169 : "[DispatcherAicpu][WaitRtsq] sqid:%d sqeCount:%u head:%u curtail:%u newTail:%u",
1170 : streamInfo.sqId, sqeCount, head, tail, newTail));
1171 :
1172 : // 轮询RTSQ直至获得足够大的剩余空间
1173 2 : u64 startUsec = GetCurAicpuTimestamp();
1174 2 : u64 lastUsec = startUsec;
1175 3 : while (((tail < head ? streamInfo.sqDepth : 0U) + tail - head + sqeCount >= streamInfo.sqDepth)
1176 3 : && (tail != head)) { // 判断RTSQ中剩余sqe空间是否足够下发
1177 : // 需要放在while循环进来后第一个执行 (获取最新的RTSQ head, 查看RTSQ的消费进度)
1178 2 : CHK_RET(QuerySqStatusByType(aicpuInfo_.devId, streamInfo.sqId, DRV_SQCQ_PROP_SQ_HEAD, head));
1179 :
1180 : // 非阻塞下发场景,rtsq队列空间不足时直接返回
1181 2 : if (isBlockLaunch == false) {
1182 1 : return HCCL_SUCCESS;
1183 : }
1184 :
1185 : // 当前流无法下发,把其他流都launch一遍,避免等待的其他流没有launch
1186 2 : for (auto it = streamMap_.begin(); it != streamMap_.end(); ++it) {
1187 1 : if (it->first != streamInfo.actualStreamId) { // 不是当前stream
1188 1 : if (it->second.IsInvalid()) { // 跳过已销毁的stream (streamMap_只增不删, 原stream销毁后副本通过shared
1189 : // invalid标志感知)
1190 0 : HCCL_WARNING(
1191 : "[DispatcherAiCpu][WaitRtsq] skip invalid stream in streamMap, streamId:%d", it->first);
1192 0 : continue;
1193 : }
1194 1 : CHK_RET(LaunchTask(it->second, false)); // 非阻塞launch
1195 : }
1196 : }
1197 :
1198 : // 等待超时
1199 1 : u64 curUsec = GetCurAicpuTimestamp();
1200 1 : if (dfxTimeOutConfig_.sqFullWaitTimeOut != 0
1201 0 : && (curUsec - startUsec > NANOSECOND_TO_SECOND * dfxTimeOutConfig_.sqFullWaitTimeOut)) {
1202 0 : HCCL_ERROR(
1203 : "[DispatcherAicpu][WaitRtsq] Rtsq full, timeout %lus. curhead:%u, sqId:%d",
1204 : dfxTimeOutConfig_.sqFullWaitTimeOut, head, streamInfo.sqId);
1205 0 : return HCCL_E_AGAIN;
1206 : }
1207 :
1208 : // 等待下发阶段,每隔30s打印一次状态
1209 1 : if (curUsec - lastUsec > NANOSECOND_TO_SECOND * dfx::kPrintSqInterval) {
1210 0 : lastUsec = curUsec;
1211 0 : HCCL_RUN_INFO(
1212 : "[DispatcherAicpu][WaitRtsq] Current state. sqid:%d, head:%u, tail:%u, sqeCount:%u", streamInfo.sqId,
1213 : head, tail, sqeCount);
1214 : }
1215 :
1216 : // 等待下发过程中出现cqe异常, 需要终止当前算子SQE的下发过程
1217 1 : if (checkOpExecStatusCallback_ != nullptr) {
1218 0 : HcclResult opExecStatus = checkOpExecStatusCallback_();
1219 0 : CHK_PRT_RET(
1220 : opExecStatus != HCCL_SUCCESS,
1221 : HCCL_ERROR(
1222 : "[DispatcherAicpu][WaitRtsq] hccl aicpu stop launch for task exception or stop command, ret:%d",
1223 : opExecStatus),
1224 : opExecStatus);
1225 : }
1226 : }
1227 :
1228 1 : return HCCL_SUCCESS;
1229 : }
1230 :
1231 0 : HcclResult DispatcherAiCpu::MemcpyRtsq(
1232 : Stream& stream, const size_t sqeCount, const uint8_t* sqeArray, const uint8_t* sqeTypeArray,
1233 : const AicpuDfxInfo* sqeDfxInfoArray, const bool profL1Enable, const std::vector<uint64_t>& profTimestamps,
1234 : const size_t profTimestampStartIdx)
1235 : {
1236 : // 检验入参
1237 0 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
1238 0 : if (sqeCount == 0) {
1239 0 : HCCL_DEBUG(
1240 : "[DispatcherAiCpu][MemcpyRtsq] no sqe, streamId:%d, sqId:%u", streamInfo.actualStreamId, streamInfo.sqId);
1241 0 : return HCCL_SUCCESS;
1242 0 : } else if (sqeCount > streamInfo.sqDepth) {
1243 0 : HCCL_ERROR(
1244 : "[DispatcherAiCpu][MemcpyRtsq] sqeCount %u should be smaller than sqDepth %u]", sqeCount,
1245 : streamInfo.sqDepth);
1246 0 : return HCCL_E_PTR;
1247 : }
1248 0 : CHK_PTR_NULL(sqeArray);
1249 0 : CHK_PTR_NULL(sqeTypeArray);
1250 0 : CHK_PTR_NULL(sqeDfxInfoArray);
1251 0 : if (profL1Enable) {
1252 : // 会访问profTimestamps[profTimestampStartIdx, profTimestampStartIdx + sqeCount - 1]
1253 0 : CHK_PRT_RET(
1254 : profTimestamps.size() == 0, HCCL_ERROR("[DispatcherAiCpu][MemcpyRtsq] empty profTimestamps"),
1255 : HCCL_E_INTERNAL);
1256 0 : CHK_PRT_RET(
1257 : profTimestampStartIdx >= profTimestamps.size(),
1258 : HCCL_ERROR(
1259 : "[DispatcherAiCpu][MemcpyRtsq] profTimestampStartIdx[%u] >= profTimestamps.size[%u]",
1260 : profTimestampStartIdx, profTimestamps.size()),
1261 : HCCL_E_INTERNAL);
1262 0 : CHK_PRT_RET(
1263 : (profTimestampStartIdx + sqeCount - 1) >= profTimestamps.size(),
1264 : HCCL_ERROR(
1265 : "[DispatcherAiCpu][MemcpyRtsq] profTimestampStartIdx[%u] + sqeCount[%u] - 1 >= profTimestamps.size[%u]",
1266 : profTimestampStartIdx, sqeCount, profTimestamps.size()),
1267 : HCCL_E_INTERNAL);
1268 : }
1269 :
1270 : // 获得RTSQ的head和tail
1271 0 : HcclSqeContext* sqeContext = stream.GetSqeContextPtr();
1272 0 : CHK_PTR_NULL(sqeContext);
1273 0 : SqeRingBuffer* sqeContextBuffer = &(sqeContext->buffer);
1274 0 : CHK_PTR_NULL(sqeContextBuffer);
1275 0 : uint32_t& head = sqeContextBuffer->sqHead;
1276 0 : uint32_t& tail = sqeContextBuffer->sqTail;
1277 :
1278 : // Dump debug information
1279 0 : const uint32_t newTail = (tail + sqeCount) % streamInfo.sqDepth;
1280 0 : HCCL_INFO(
1281 : "[DispatcherAicpu][MemcpyRtsq] before memcpy, sqid:%d sqeCount:%u head:%u curtail:%u newTail:%u",
1282 : streamInfo.sqId, sqeCount, head, tail, newTail);
1283 :
1284 : // 准备memcpy中目的末端基地址 (RTSQ从tail开始拷贝, [head, tail)为待执行SQE)
1285 0 : uint8_t* rtsqSqeTailBaseAddr = reinterpret_cast<uint8_t*>(streamInfo.sqBaseAddr) + tail * HCCL_SQE_SIZE;
1286 0 : uint8_t* mirrorRtsqSqeTailBaseAddr = sqeContextBuffer->rtsMirrorBuffer + tail * HCCL_SQE_SIZE;
1287 0 : uint8_t* rtsqSqeTypeTailBaseAddr = sqeContextBuffer->rtsqSqeType + tail;
1288 0 : AicpuDfxInfo* rtsqDfxInfoTailBaseAddr = sqeContextBuffer->rtsDfxInfo + tail;
1289 :
1290 0 : uint32_t tailLeft = streamInfo.sqDepth - tail; // RTSQ tail到buffer末端的剩余空间 (不包括buffer前端到head的剩余空间)
1291 0 : HCCL_INFO(
1292 : "[DispatcherAicpu][MemcpyRtsq] cpy sqe, tailLeft:%u, sqeCount:%u, streamId:%u", tailLeft, sqeCount,
1293 : stream.id());
1294 0 : if (sqeCount <= tailLeft) { // buffer末端剩余空间放得下新增sqe
1295 : // 向buffer末端拷贝sqeCount个SQE信息
1296 :
1297 : // 拷贝SQE内容到RTSQ
1298 0 : CHK_SAFETY_FUNC_RET(
1299 : memcpy_s(rtsqSqeTailBaseAddr, tailLeft * HCCL_SQE_SIZE, sqeArray, sqeCount * HCCL_SQE_SIZE));
1300 :
1301 : // 拷贝SQE内容到RTSQ mirror
1302 0 : CHK_SAFETY_FUNC_RET(
1303 : memcpy_s(mirrorRtsqSqeTailBaseAddr, tailLeft * HCCL_SQE_SIZE, sqeArray, sqeCount * HCCL_SQE_SIZE));
1304 :
1305 : // 拷贝SQE类型
1306 0 : CHK_SAFETY_FUNC_RET(memcpy_s(rtsqSqeTypeTailBaseAddr, tailLeft, sqeTypeArray, sqeCount));
1307 :
1308 : // 拷贝SQE DfxInfo
1309 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1310 : rtsqDfxInfoTailBaseAddr, tailLeft * sizeof(AicpuDfxInfo), sqeDfxInfoArray,
1311 : sqeCount * sizeof(AicpuDfxInfo)));
1312 : } else { // 需要buffer末端和首端的剩余空间
1313 : // 先向buffer末端拷贝tailLeft个SQE信息, 再向buffer首端拷贝sqeCount-tailLeft个SQE信息
1314 :
1315 : // 拷贝SQE内容到RTSQ
1316 0 : CHK_SAFETY_FUNC_RET(
1317 : memcpy_s(rtsqSqeTailBaseAddr, tailLeft * HCCL_SQE_SIZE, sqeArray, tailLeft * HCCL_SQE_SIZE));
1318 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1319 : reinterpret_cast<uint8_t*>(streamInfo.sqBaseAddr), streamInfo.sqDepth * HCCL_SQE_SIZE,
1320 : sqeArray + tailLeft * HCCL_SQE_SIZE, (sqeCount - tailLeft) * HCCL_SQE_SIZE));
1321 :
1322 : // 拷贝SQE内容到RTSQ mirror
1323 0 : CHK_SAFETY_FUNC_RET(
1324 : memcpy_s(mirrorRtsqSqeTailBaseAddr, tailLeft * HCCL_SQE_SIZE, sqeArray, tailLeft * HCCL_SQE_SIZE));
1325 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1326 : sqeContextBuffer->rtsMirrorBuffer, streamInfo.sqDepth * HCCL_SQE_SIZE, sqeArray + tailLeft * HCCL_SQE_SIZE,
1327 : (sqeCount - tailLeft) * HCCL_SQE_SIZE));
1328 :
1329 : // 拷贝SQE type
1330 0 : CHK_SAFETY_FUNC_RET(memcpy_s(rtsqSqeTypeTailBaseAddr, tailLeft, sqeTypeArray, tailLeft));
1331 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1332 : sqeContextBuffer->rtsqSqeType, streamInfo.sqDepth, sqeTypeArray + tailLeft, (sqeCount - tailLeft)));
1333 :
1334 : // 拷贝SQE DfxInfo
1335 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1336 : rtsqDfxInfoTailBaseAddr, tailLeft * sizeof(AicpuDfxInfo), sqeDfxInfoArray,
1337 : tailLeft * sizeof(AicpuDfxInfo)));
1338 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1339 : sqeContextBuffer->rtsDfxInfo, streamInfo.sqDepth * sizeof(AicpuDfxInfo), sqeDfxInfoArray + tailLeft,
1340 : (sqeCount - tailLeft) * sizeof(AicpuDfxInfo)));
1341 : }
1342 :
1343 : // 更新RTSQ ring buffer的tail
1344 0 : CHK_RET(ConfigSqStatusByType(aicpuInfo_.devId, streamInfo.sqId, DRV_SQCQ_PROP_SQ_TAIL, newTail));
1345 0 : tail = newTail;
1346 0 : PLF_CONFIG_INFO(
1347 : PLF_TASK, "%s success, sqid:%d, sqe_num:%u, curHead:%u, curtail:%u", __func__, streamInfo.sqId, sqeCount, head,
1348 : tail);
1349 :
1350 : // 上报profiling信息
1351 0 : if (profL1Enable) {
1352 : // Cache hit下SQE ring buffer中[tail-cnt, tail)为待下发SQE, 其数量一定为0 (否则更新tailSqeIdx后,
1353 : // 会导致待下发SQE未下发, 而已下发SQE重复下发)
1354 0 : CHK_PRT_RET(
1355 : sqeContextBuffer->sqeCnt != 0,
1356 : HCCL_ERROR(
1357 : "[DispatcherAicpu][MemcpyRtsq] sqeContextBuffer->sqeCnt[%u] should be zero!", sqeContextBuffer->sqeCnt),
1358 : HCCL_E_INTERNAL);
1359 :
1360 : // 上报flip placeholder的profiling信息
1361 0 : if ((*sqeTypeArray) == SqeType::FLIP_PLACEHOLDER_SQE) {
1362 0 : CHK_PRT_RET(
1363 : sqeCount != 1, HCCL_ERROR("[DispatcherAicpu][MemcpyRtsq] sqeCount[%u] should be 1!", sqeCount),
1364 : HCCL_E_INTERNAL);
1365 :
1366 : // 注意: 参考AddFlipTask, 先上报flip task (提醒profiling翻转taskid), 之后再拷贝到SQE ring buffer
1367 : // (捕捉placeholder SQE相关的profiling信息) 注意:
1368 : // ProfilingManager::TaskProfilingCallBack->ReportFilpTask不会扫描SQE ring buffer,
1369 : // 也不会更新其中的streamToSqeIdxMap_
1370 0 : if (callback_ != nullptr) {
1371 0 : const rtStarsPlaceHolderSqe_t* placeholderSqePtr
1372 : = reinterpret_cast<const rtStarsPlaceHolderSqe_t*>(sqeArray);
1373 : hccl::FlipTaskPara para(
1374 0 : stream.id(), placeholderSqePtr->header.taskId, placeholderSqePtr->u.flip_task_info.flipNumReport);
1375 0 : hccl::TaskPara taskPara(TaskType::TASK_FLIP, para);
1376 0 : callback_(callBackUserPtr_, (void*)&taskPara, sizeof(struct TaskPara));
1377 0 : }
1378 : }
1379 :
1380 : // 循环拷贝cached SQE到SQE ring buffer中
1381 0 : size_t reportSqeCount = 0;
1382 0 : while (reportSqeCount < sqeCount) {
1383 0 : CHK_PRT_RET(
1384 : sqeContextBuffer->tailSqeIdx > HCCL_SQE_MAX_CNT,
1385 : HCCL_ERROR(
1386 : "[DispatcherAicpu][MemcpyRtsq] tailSqeIdx[%u] > HCCL_SQE_MAX_CNT[%u]", sqeContextBuffer->tailSqeIdx,
1387 : HCCL_SQE_MAX_CNT),
1388 : HCCL_E_INTERNAL);
1389 0 : const size_t sqeTailLeft = HCCL_SQE_MAX_CNT - sqeContextBuffer->tailSqeIdx;
1390 0 : if (sqeTailLeft > 0) {
1391 : // 准备profiling上报的目的末端基地址 (SQE ring buffer从tail开始拷贝)
1392 0 : uint8_t* sqeLocalBuffTailBaseAddr
1393 0 : = sqeContextBuffer->localBuff + sqeContextBuffer->tailSqeIdx * HCCL_SQE_SIZE;
1394 0 : uint8_t* sqeTypeTailBaseAddr = sqeContextBuffer->sqeType + sqeContextBuffer->tailSqeIdx;
1395 0 : AicpuDfxInfo* dfxInfoTailBaseAddr = sqeContextBuffer->dfxInfo + sqeContextBuffer->tailSqeIdx;
1396 0 : uint64_t* profTimestapTailBaseAddr = sqeContextBuffer->profTimestap + sqeContextBuffer->tailSqeIdx;
1397 :
1398 : // 向SQE ring buffer末端拷贝SQE信息[reportSqeCount, reportSqeCount + tmpSqeCount - 1]
1399 : // (只用于profiling上报, 不会下发)
1400 0 : const size_t tmpSqeCount = std::min(sqeCount - reportSqeCount, sqeTailLeft);
1401 0 : HCCL_INFO(
1402 : "[DispatcherAicpu][MemcpyRtsq] report sqe profiling, sqeCount[%u] reportSqeCount[%u] "
1403 : "tailSqeIdx[%u] sqeTailLeft[%u] tmpSqeCount[%u]",
1404 : sqeCount, reportSqeCount, sqeContextBuffer->tailSqeIdx, sqeTailLeft, tmpSqeCount);
1405 :
1406 : // 拷贝SQE内容
1407 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1408 : sqeLocalBuffTailBaseAddr, sqeTailLeft * HCCL_SQE_SIZE, sqeArray + reportSqeCount * HCCL_SQE_SIZE,
1409 : tmpSqeCount * HCCL_SQE_SIZE));
1410 :
1411 : // 拷贝SQE类型
1412 0 : CHK_SAFETY_FUNC_RET(
1413 : memcpy_s(sqeTypeTailBaseAddr, sqeTailLeft, sqeTypeArray + reportSqeCount, tmpSqeCount));
1414 :
1415 : // 拷贝SQE DfxInfo
1416 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1417 : dfxInfoTailBaseAddr, sqeTailLeft * sizeof(AicpuDfxInfo), sqeDfxInfoArray + reportSqeCount,
1418 : tmpSqeCount * sizeof(AicpuDfxInfo)));
1419 :
1420 : // 拷贝SQE timestamp
1421 0 : CHK_SAFETY_FUNC_RET(memcpy_s(
1422 : profTimestapTailBaseAddr, sqeTailLeft * sizeof(uint64_t),
1423 : profTimestamps.data() + profTimestampStartIdx + reportSqeCount, tmpSqeCount * sizeof(uint64_t)));
1424 :
1425 : // 注意: sqeContextBuffer->sqeCnt不更新, 仍然为0 (即拷贝的SQE信息为已下发待上报), 避免SQE重复下发
1426 0 : sqeContextBuffer->tailSqeIdx += static_cast<uint16_t>(tmpSqeCount);
1427 0 : reportSqeCount += tmpSqeCount;
1428 : } else {
1429 : // 注意: SQE ring buffer中待下发SQE数量一定为0, 不需要调用LaunchTask将待下发变成已下发待上报,
1430 : // 可以直接上报profiling将已下发待上报变成已上报 注意: 调用后,
1431 : // ProfilingManager::StartReportSqeIdx为HCCL_SQE_MAX_CNT
1432 0 : if (callback_ != nullptr) {
1433 0 : hccl::AiCPUStreamTasks para(stream.id(), reinterpret_cast<void*>(sqeContext));
1434 0 : hccl::TaskPara taskPara(TaskType::TASK_BATCH_REPORT, para);
1435 0 : callback_(callBackUserPtr_, (void*)&taskPara, sizeof(struct TaskPara));
1436 0 : }
1437 :
1438 : // SQE ring buffer中所有SQE均为已上报 -> 清理SQE ring buffer
1439 0 : HCCL_INFO("[DispatcherAicpu][MemcpyRtsq] Sqe index to %u, need clear", HCCL_SQE_MAX_CNT);
1440 0 : CHK_PRT_RET(
1441 : sqeContextBuffer->sqeCnt != 0,
1442 : HCCL_ERROR(
1443 : "[DispatcherAicpu][MemcpyRtsq] Sqe index to %u, but sqeCnt[%u] is not 0", HCCL_SQE_MAX_CNT,
1444 : sqeContextBuffer->sqeCnt),
1445 : HCCL_E_INTERNAL);
1446 0 : CHK_RET(stream.ClearLocalBuff()); // 会将stream.sqeContextBuffer中的sqeCnt和tailSqeIdx设置为0
1447 0 : CHK_PRT_RET(
1448 : sqeContextBuffer->sqeCnt != 0,
1449 : HCCL_ERROR(
1450 : "[DispatcherAicpu][MemcpyRtsq] sqeCnt[%u] should be 0 after clear", sqeContextBuffer->sqeCnt),
1451 : HCCL_E_INTERNAL);
1452 0 : CHK_PRT_RET(
1453 : sqeContextBuffer->tailSqeIdx != 0,
1454 : HCCL_ERROR(
1455 : "[DispatcherAicpu][MemcpyRtsq] tailSqeIdx[%u] should be 0 after clear",
1456 : sqeContextBuffer->tailSqeIdx),
1457 : HCCL_E_INTERNAL);
1458 :
1459 : // 参考HcclCommAicpu::ClearLocalBuff, 调用Stream::ClearLocalBuff后,
1460 : // 应该调用ProfilingManager::UpdateStartReportSqeIdx手动将ProfilingManager::StartReportSqeIdx设置为0
1461 : // 注意: 由于platform暂未将UpdateStartReportSqeIdx作为回调函数传入, 无法直接调用此framework函数 ->
1462 : // 通过callback_ (即ProfilingManager::TaskProfilingCallBack)
1463 : // 间接将ProfilingManager::StartReportSqeIdx设置为0 注意:
1464 : // 由于调用前ProfilingManager::StartReportSqeIdx为HCCL_SQE_MAX_CNT, tailSqeIdx为0,
1465 : // 即从startIdx=HCCL_SQE_MAX_CNT到endIdx=0, ProfilingManager不会进入profiling上报代码,
1466 : // 而是只会调用UpdateStartReportSqeIdx设置StartReportSqeIdx为0
1467 0 : if (callback_ != nullptr) {
1468 0 : HCCL_INFO("[DispatcherAicpu][MemcpyRtsq] re-invoke callback_ to reset StartReportSqeIdx as 0 in "
1469 : "ProfilingManager");
1470 :
1471 0 : hccl::AiCPUStreamTasks para(stream.id(), reinterpret_cast<void*>(sqeContext));
1472 0 : hccl::TaskPara taskPara(TaskType::TASK_BATCH_REPORT, para);
1473 0 : callback_(callBackUserPtr_, (void*)&taskPara, sizeof(struct TaskPara));
1474 0 : }
1475 : }
1476 : }
1477 : }
1478 :
1479 0 : return HCCL_SUCCESS;
1480 : }
1481 :
1482 0 : HcclResult DispatcherAiCpu::AddFlipTask(Stream& stream)
1483 : {
1484 0 : HcclSqeContext* sqeContext = stream.GetSqeContextPtr();
1485 0 : CHK_PTR_NULL(sqeContext);
1486 0 : SqeRingBuffer* sqeContextBuffer = &(sqeContext->buffer);
1487 0 : CHK_PTR_NULL(sqeContextBuffer);
1488 0 : uint16_t flipNum = sqeContextBuffer->filpNum;
1489 0 : uint16_t taskId = sqeContextBuffer->tailSqeTaskId;
1490 :
1491 0 : if (callback_ != nullptr) {
1492 0 : hccl::FlipTaskPara para(stream.id(), taskId, flipNum);
1493 0 : hccl::TaskPara taskPara(TaskType::TASK_FLIP, para);
1494 0 : callback_(callBackUserPtr_, (void*)&taskPara, sizeof(struct TaskPara));
1495 0 : }
1496 :
1497 0 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
1498 :
1499 0 : uint8_t* sqeBufferAddr = nullptr;
1500 0 : uint8_t* sqeTypeAddr = nullptr;
1501 0 : uint8_t* sqeDfxInfoAddr = nullptr;
1502 0 : CHK_RET(stream.GetNextSqeBufferAddr(sqeBufferAddr, sqeTypeAddr, sqeDfxInfoAddr, taskId));
1503 :
1504 0 : AicpuDfxInfo* const dfxInfo = (AicpuDfxInfo* const)sqeDfxInfoAddr;
1505 0 : dfxInfo->opRingBufferIdx = opRingBufferIdx_;
1506 0 : dfxInfo->remoteRank = INVALID_VALUE_RANKID;
1507 0 : dfxInfo->notifyId = INVALID_VALUE_RANKID;
1508 0 : addOneFlipPlaceHolderSqe_(streamInfo.actualStreamId, flipNum, taskId, sqeBufferAddr, sqeTypeAddr);
1509 :
1510 0 : PLF_CONFIG_INFO(
1511 : PLF_TASK, "%s para: taskId[%u] streamId[%u] flipNum[%u]", __func__, taskId, streamInfo.actualStreamId, flipNum);
1512 0 : return HCCL_SUCCESS;
1513 : }
1514 :
1515 0 : HcclResult DispatcherAiCpu::AddRetryPreamble(Stream& stream) { return AddFlipTask(stream); }
1516 :
1517 22 : void DispatcherAiCpu::SaveStreamInfo(hccl::Stream& stream)
1518 : {
1519 22 : const HcclComStreamInfo& streamInfo = stream.GetHcclStreamInfo();
1520 22 : auto it = streamMap_.find(streamInfo.actualStreamId);
1521 22 : if (it == streamMap_.end()) {
1522 17 : streamMap_.insert({streamInfo.actualStreamId, stream});
1523 17 : HCCL_INFO("[DispatcherAiCpu][SaveStreamInfo] stream id[%d]", streamInfo.actualStreamId);
1524 5 : } else if (it->second.IsInvalid()) {
1525 : // stream id复用: 旧stream已销毁(IsInvalid=true), 用新stream覆盖, 否则dispatcher会一直跳过该id
1526 0 : it->second = stream;
1527 0 : HCCL_INFO(
1528 : "[DispatcherAiCpu][SaveStreamInfo] refresh invalidated stream id stream id[%d]", streamInfo.actualStreamId);
1529 : }
1530 44 : return;
1531 : }
1532 :
1533 2 : HcclResult DispatcherAiCpu::StreamSync(Stream& stream)
1534 : {
1535 2 : uint32_t head = 0;
1536 2 : uint32_t tail = 0;
1537 : const HcclComStreamInfo* streamInfo;
1538 2 : u64 startUsec = GetCurAicpuTimestamp();
1539 2 : u64 lastUsec = startUsec;
1540 2 : CHK_RET(stream.GetStreamInfo(streamInfo));
1541 :
1542 2 : CHK_RET(QuerySqStatusByType(aicpuInfo_.devId, streamInfo->sqId, DRV_SQCQ_PROP_SQ_TAIL, tail));
1543 2 : HCCL_INFO("StreamSync aicpu stream sqid[%d] tail[%u]", streamInfo->sqId, tail);
1544 : do {
1545 2 : CHK_RET(QuerySqStatusByType(aicpuInfo_.devId, streamInfo->sqId, DRV_SQCQ_PROP_SQ_HEAD, head));
1546 2 : u64 curUsec = GetCurAicpuTimestamp();
1547 2 : if (curUsec - startUsec > NANOSECOND_TO_SECOND * dfxTimeOutConfig_.sqeTimeOutTimeOut) {
1548 1 : HCCL_ERROR(
1549 : "stream sync timeout %lus. curhead:%u, curtall:%u, sqId:%d", dfxTimeOutConfig_.sqeTimeOutTimeOut, head,
1550 : tail, streamInfo->sqId);
1551 1 : return HCCL_E_TIMEOUT;
1552 : }
1553 :
1554 : // 等待下发阶段,每隔30s打印一次状态
1555 1 : if (curUsec - lastUsec > NANOSECOND_TO_SECOND * dfx::kPrintSqInterval) {
1556 0 : lastUsec = curUsec;
1557 0 : HCCL_RUN_INFO("[StreamSync]Current state. sqid:%d, head:%u, tail:%u", streamInfo->sqId, head, tail);
1558 : }
1559 1 : } while (head != tail);
1560 :
1561 1 : return HCCL_SUCCESS;
1562 : }
1563 :
1564 5 : u64 DispatcherAiCpu::CalcDbAddr(u32 dbindex)
1565 : {
1566 5 : u64 dbAddr = 0;
1567 5 : if (aicpuInfo_.devType == DevType::DEV_TYPE_910_93) {
1568 : // 910_93 HCCS_SW 组网
1569 2 : constexpr u64 roceBaseAddr = 0x202000000000ULL;
1570 2 : constexpr u64 roceVfDbCfg0Reg = 0x230ULL;
1571 2 : constexpr u64 chipAddrOffset = 0x20000000000ULL;
1572 2 : constexpr u64 dieAddrOffset = 0x10000000000ULL;
1573 2 : constexpr u32 dbDieIdMask = 0x00ff0000;
1574 2 : constexpr u32 dbDieIdShift = 16; // 16 is dbDieIdShift
1575 2 : dbAddr = roceBaseAddr + roceVfDbCfg0Reg + chipAddrOffset * aicpuInfo_.chipId
1576 2 : + dieAddrOffset * ((dbindex & dbDieIdMask) >> dbDieIdShift);
1577 : } else {
1578 3 : constexpr u64 roceBaseAddr = 0x2000000000ULL;
1579 3 : constexpr u64 roceVfDbCfg0Reg = 0x230ULL;
1580 3 : constexpr u64 chipAddrOffset = 0x80000000000ULL;
1581 3 : constexpr u64 dieAddrOffset = 0x10000000000ULL;
1582 3 : constexpr u32 dbDieIdMask = 0x00ff0000;
1583 3 : constexpr u32 dbDieIdShift = 16; // 16 is dbDieIdShift
1584 3 : dbAddr = roceBaseAddr + roceVfDbCfg0Reg + chipAddrOffset * aicpuInfo_.chipId
1585 3 : + dieAddrOffset * ((dbindex & dbDieIdMask) >> dbDieIdShift);
1586 : }
1587 :
1588 5 : HCCL_DEBUG(
1589 : "%s dbindex:%u, devType:%u, chipId:%lld, dbAddr:%llu", __func__, dbindex, aicpuInfo_.devType, aicpuInfo_.chipId,
1590 : dbAddr);
1591 5 : return dbAddr;
1592 : }
1593 :
1594 449 : void DispatcherAiCpu::InitTimeOutConfig()
1595 : {
1596 449 : dfxTimeOutConfig_.useCredit = false;
1597 449 : dfxTimeOutConfig_.sqeTimeOutTimeOut = GetMaxNotifyWaitTime();
1598 449 : dfxTimeOutConfig_.sqeCreditTimeOut = RT_STARS_NEVER_TIMEOUT_KERNEL_CREDIT;
1599 449 : dfxTimeOutConfig_.sqeWaitTimeOut = dfx::kKfcTimeOut;
1600 449 : dfxTimeOutConfig_.sqFullWaitTimeOut = dfx::kSqFullWaitTimeOut;
1601 449 : HCCL_INFO(
1602 : "[DispatcherAiCpu][InitTimeOutConfig]DFX timeout config init successfully with details: [%s]",
1603 : dfxTimeOutConfig_.ToString().c_str());
1604 449 : }
1605 : } // namespace hccl
|