LCOV - code coverage report
Current view: top level - legacy/ascend910/framework/device/aicpu_kfc/algorithm - aicpu_reduce_scatter.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.7 % 308 227
Test Date: 2026-08-18 17:47:01 Functions: 50.0 % 12 6

            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 "aicpu_reduce_scatter.h"
      12              : 
      13              : namespace {
      14              : template <typename T>
      15            0 : inline T MathCeil(T num1, T num2)
      16              : {
      17            0 :     if (num2 == 0) {
      18            0 :         return num1;
      19              :     }
      20            0 :     return (num1 + num2 - 1) / num2;
      21              : }
      22              : 
      23              : template <typename T>
      24            0 : inline T AlignUp(T num1, T num2)
      25              : {
      26            0 :     return MathCeil(num1, num2) * num2;
      27              : }
      28              : } // namespace
      29              : 
      30           21 : HcclResult AicpuReduceScatter::RunAlgorithm(
      31              :     HcclReduceOp opType, void* sendBuffer, void* recvBuffer, u64 dataCount, HcclDataType dataType, u64 strideLen,
      32              :     AivAicpuOpParam* /* nextTask */)
      33              : {
      34           21 :     CHK_PTR_NULL(ctx_);
      35              :     // dataCount 为tile的输入的数据量(scatter前)
      36           21 :     if (dataCount % rankNum_ != 0) { // 每个tile数据量必须能均分至每张卡
      37            2 :         HCCL_ERROR("Reduce scatter dataCount %lu max be multiple of rankNum_.", dataCount);
      38            2 :         return HCCL_E_NOT_SUPPORT;
      39              :     }
      40              : 
      41           19 :     switch (ctx_->commAlg) {
      42           15 :         case CommAlgType::COMM_ALG_FULL_MESH: {
      43           15 :             if (ctx_->determinism) {
      44            6 :                 return RunDeterministicReduceScatterLocal(
      45            6 :                     opType, sendBuffer, recvBuffer, dataCount, dataType, strideLen);
      46              :             }
      47            9 :             return RunReduceScatterWriteMode(opType, sendBuffer, recvBuffer, dataCount, dataType, strideLen);
      48              :         }
      49            2 :         case CommAlgType::COMM_ALG_DOUBLE_RING: {
      50            2 :             return RunDoubleRingReduceScatter(
      51            2 :                 opType, reinterpret_cast<u64>(sendBuffer), reinterpret_cast<u64>(recvBuffer), dataCount, dataType);
      52              :         }
      53            2 :         case CommAlgType::COMM_ALG_SWITCH_WING: {
      54            2 :             return RunSwitchReduceScatter(
      55            2 :                 opType, reinterpret_cast<u64>(sendBuffer), reinterpret_cast<u64>(recvBuffer), dataCount, dataType);
      56              :         }
      57            0 :         default: {
      58            0 :             HCCL_ERROR("CommAlg %d is not supported.", ctx_->commAlg);
      59            0 :             return HCCL_E_NOT_SUPPORT;
      60              :         }
      61              :     }
      62              : }
      63              : 
      64            6 : HcclResult AicpuReduceScatter::RunDeterministicReduceScatterLocal(
      65              :     HcclReduceOp opType, void* sendBuffer, void* recvBuffer, u64 dataCount, HcclDataType dataType, u64 strideLen)
      66              : {
      67            6 :     u8* curInputPtr = static_cast<u8*>(sendBuffer);
      68            6 :     u8* curOutputPtr = static_cast<u8*>(recvBuffer);
      69            6 :     u64 windowSize = ctx_->windowSize;
      70            6 :     u64 countLeft = dataCount / rankNum_;
      71            6 :     u64 maxCountPerLoop = windowSize / unitSize_ / rankNum_;
      72            6 :     u64 inputOffset = 0;
      73            6 :     u64 outputOffset = 0;
      74            6 :     u32 loopIdx = 0;
      75            6 :     u64 displs[AC_MAX_RANK_NUM] = {0};
      76            6 :     u64 windowSlices = rankId_ * countLeft * unitSize_;
      77              : 
      78           54 :     for (u32 i = 0; i < ctx_->rankNum; i++) {
      79           48 :         displs[i] = strideLen * i * unitSize_;
      80              :     }
      81              : 
      82           14 :     while (countLeft > 0) {
      83            8 :         curInputPtr += inputOffset;
      84            8 :         curOutputPtr += outputOffset;
      85            8 :         u64 curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
      86            8 :         u64 curSize = curCount * unitSize_; // 单位 byte
      87            8 :         windowSlices = rankId_ * curSize;
      88              : 
      89            8 :         HCCL_DEBUG(
      90              :             "RunDeterministicReduceScatterLocal: countLeft = %llu, loop %u, curInputPtr[%p], curOutputPtr[%p],"
      91              :             "curCount[%llu], curSize[%llu], strideLen[%llu]",
      92              :             countLeft, loopIdx++, curInputPtr, curOutputPtr, curCount, curSize, strideLen);
      93              :         // 1. 片内数据拷贝:send->win
      94            8 :         TaskOrchestrator::SelfCpySnd2Win(
      95            8 :             curInputPtr, curSize, displs[rankId_], windowSlices, HCCL_REDUCE_RESERVED, dataType);
      96              : 
      97              :         // 2. 前同步
      98            8 :         TaskOrchestrator::DoPreSync();
      99              : 
     100              :         // 3. 跨片SDMA,send->对端win
     101            8 :         TaskOrchestrator::IpcCpySnd2Win(curInputPtr, curSize, displs, windowSlices, HCCL_REDUCE_RESERVED, dataType);
     102              : 
     103              :         // 4. 后同步
     104            8 :         TaskOrchestrator::DoPostSync();
     105              : 
     106              :         // 5. 折半计算
     107            8 :         TaskOrchestrator::SelfLocalReduce(curSize, opType, dataType);
     108              : 
     109              :         // 6. 片内数据拷贝 本端win->当前rcv buff
     110            8 :         TaskOrchestrator::SelfCpyWin2Rcv(curOutputPtr, curSize, 0, 0, HCCL_REDUCE_RESERVED, dataType);
     111              : 
     112            8 :         TaskOrchestrator::LaunchTasks();
     113              : 
     114            8 :         countLeft -= curCount;
     115            8 :         inputOffset = curSize;
     116            8 :         outputOffset = curSize;
     117              :     }
     118            6 :     return HCCL_SUCCESS;
     119              : }
     120              : 
     121            9 : HcclResult AicpuReduceScatter::RunReduceScatterWriteMode(
     122              :     HcclReduceOp opType, void* sendBuffer, void* recvBuffer, u64 dataCount, HcclDataType dataType, u64 strideLen)
     123              : {
     124            9 :     dataCount /= rankNum_;
     125              : 
     126            9 :     u64 windowSize = ctx_->windowSize;
     127            9 :     u64 maxCountPerLoop = windowSize / unitSize_; // 中转内存单次最多能够接受的output count
     128              : 
     129            9 :     uint8_t* curInputPtr = static_cast<uint8_t*>(sendBuffer);
     130            9 :     uint8_t* curOutputPtr = static_cast<uint8_t*>(recvBuffer);
     131            9 :     u64 inputOffset = 0;
     132            9 :     u64 outputOffset = 0;
     133            9 :     u64 countLeft = dataCount;
     134              : 
     135            9 :     u64 displs[AC_MAX_RANK_NUM] = {0};
     136            9 :     u64 windowOffsets[AC_MAX_RANK_NUM] = {0};
     137           81 :     for (u32 i = 0; i < rankNum_; i++) {
     138           72 :         displs[i] = i * strideLen * unitSize_;
     139           72 :         windowOffsets[i] = (i * strideLen * unitSize_) % HCCL_COPY_ALIGN;
     140              :     }
     141              : 
     142            9 :     uint32_t loopIdx = 0;
     143           17 :     while (countLeft > 0) {
     144            8 :         curInputPtr += inputOffset;
     145            8 :         curOutputPtr += outputOffset;
     146            8 :         u64 curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
     147            8 :         u64 curSize = curCount * unitSize_; // 单位 byte
     148              : 
     149            8 :         HCCL_DEBUG(
     150              :             "RunReduceScatterWriteMode: loop %u, curInputPtr[%p], curOutputPtr[%p], curCount[%llu], curSize[%llu], "
     151              :             "strideLen[%llu]",
     152              :             loopIdx++, curInputPtr, curOutputPtr, curCount, curSize, strideLen);
     153              : 
     154              :         // 1. 片内数据 snd->win
     155            8 :         CHK_RET(TaskOrchestrator::SelfCpySnd2Win(
     156              :             curInputPtr, curSize, displs[rankId_], windowOffsets[rankId_], HCCL_REDUCE_RESERVED, dataType)); // 1, 0
     157              :         // 2. 前同步
     158            8 :         CHK_RET(TaskOrchestrator::DoPreSync()); // 15 sqe, 35
     159              : 
     160              :         // 3. 跨片SDMA send->其他window
     161            8 :         CHK_RET(TaskOrchestrator::IpcCpySnd2Win(curInputPtr, curSize, displs, windowOffsets, opType,
     162              :                                                 dataType)); // 0, 7
     163              : 
     164              :         // 4. 后同步
     165            8 :         CHK_RET(TaskOrchestrator::DoPostSync()); // 8, 21
     166              : 
     167              :         // 5. 片内数据 拷贝到recv
     168            8 :         CHK_RET(TaskOrchestrator::SelfCpyWin2Rcv(
     169              :             curOutputPtr, curSize, windowOffsets[rankId_], 0, HCCL_REDUCE_RESERVED,
     170              :             dataType)); // 1, 0
     171              : 
     172            8 :         CHK_RET(TaskOrchestrator::LaunchTasks()); // 25, 63
     173              : 
     174            8 :         countLeft -= curCount;
     175            8 :         inputOffset = curSize;
     176            8 :         outputOffset = curSize;
     177              :     }
     178              : 
     179            9 :     return HCCL_SUCCESS;
     180              : }
     181              : 
     182            0 : HcclResult AicpuReduceScatter::RunReduceScatterReadMode(
     183              :     HcclReduceOp opType, void* sendBuffer, void* recvBuffer, u64 dataCount, HcclDataType dataType)
     184              : {
     185            0 :     uint32_t dataSize = dataCount * unitSize_; // 输入大小
     186            0 :     u64 scatterSize = dataSize / rankNum_;     // 输出大小
     187              : 
     188            0 :     HCCL_DEBUG(
     189              :         "RunReduceScatterReadMode: sendBuffer[%p], recvBuffer[%p], dataCount[%llu], dataSize[%llu]", sendBuffer,
     190              :         recvBuffer, dataCount, dataSize);
     191              : 
     192              :     // 1. 片内数据 snd->win 一次性全拷贝
     193            0 :     CHK_RET(TaskOrchestrator::SelfCpySnd2Win(sendBuffer, dataSize, 0, 0, HCCL_REDUCE_RESERVED, dataType));
     194              :     // 2. 前同步
     195            0 :     CHK_RET(TaskOrchestrator::DoPreSync()); // 15 sqe, 35
     196              : 
     197              :     // 3. 片内win->recv   实测放在和跨片sdma并行时性能更好
     198            0 :     CHK_RET(TaskOrchestrator::SelfCpyWin2Rcv(
     199              :         recvBuffer, scatterSize, rankId_ * scatterSize, 0, HCCL_REDUCE_RESERVED, dataType));
     200              : 
     201              :     // 3. 跨片SDMA 其他win->recv
     202            0 :     u64 winOffsets[AC_MAX_RANK_NUM] = {0};
     203            0 :     for (size_t i = 0; i < rankNum_; i++) {
     204            0 :         winOffsets[i] = rankId_ * scatterSize;
     205              :     }
     206            0 :     CHK_RET(TaskOrchestrator::IpcCpyWin2Rcv(recvBuffer, scatterSize, winOffsets, nullptr, opType, dataType));
     207              : 
     208              :     // 4. 后同步
     209            0 :     CHK_RET(TaskOrchestrator::DoPostSync()); // 8 sqe, 21
     210              : 
     211            0 :     CHK_RET(TaskOrchestrator::LaunchTasks()); // 25, 63
     212              : 
     213            0 :     return HCCL_SUCCESS;
     214              : }
     215              : 
     216            0 : std::vector<Slice> AicpuReduceScatter::PrepareMeshSlice(u64 dataSize, uint32_t rankNum_)
     217              : {
     218            0 :     std::vector<Slice> meshSlices;
     219            0 :     uint32_t roundCnt = rankNum_ - 1;
     220              : 
     221            0 :     u64 sizePerRound = AlignUp<u64>((dataSize + roundCnt - 1) / roundCnt, HCCL_MIN_SLICE_ALIGN);
     222            0 :     int64_t rankResidueSize = static_cast<int64_t>(dataSize);
     223              : 
     224            0 :     while (rankResidueSize > 0) {
     225            0 :         Slice singleRoundSlice;
     226            0 :         singleRoundSlice.offset = dataSize - rankResidueSize;
     227            0 :         singleRoundSlice.size = std::min<u64>(sizePerRound, rankResidueSize);
     228            0 :         rankResidueSize -= singleRoundSlice.size;
     229            0 :         meshSlices.push_back(singleRoundSlice);
     230              :     }
     231              : 
     232            0 :     for (const auto& slice : meshSlices) {
     233            0 :         HCCL_DEBUG("Slice offset:%lu, size:%lu", slice.offset, slice.size);
     234              :     }
     235            0 :     return meshSlices;
     236            0 : }
     237              : 
     238            0 : HcclResult AicpuReduceScatter::RunDeterministicReduceScatter(
     239              :     HcclReduceOp opType, void* sendBuffer, void* recvBuffer, u64 dataCount, HcclDataType dataType, u64 strideCount)
     240              : {
     241            0 :     HCCL_INFO("RunDeterministicReduceScatter strideCount:%u", strideCount);
     242            0 :     dataCount /= rankNum_;
     243              : 
     244            0 :     u64 maxCountPerLoop = ctx_->windowSize / (rankNum_ * unitSize_); // 中转内存单次最多能够接受的output count
     245            0 :     u64 curCount = 0;
     246            0 :     uint8_t* curInputPtr = static_cast<uint8_t*>(sendBuffer);
     247            0 :     uint8_t* curOutputPtr = static_cast<uint8_t*>(recvBuffer);
     248            0 :     for (u64 countLeft = dataCount, inputOffset = 0, outputOffset = 0; countLeft > 0; countLeft -= curCount) {
     249            0 :         curInputPtr += inputOffset;
     250            0 :         curOutputPtr += outputOffset;
     251            0 :         curCount = ((countLeft * unitSize_ * rankNum_) > ctx_->windowSize) ? maxCountPerLoop : countLeft;
     252            0 :         u64 curSize = curCount * unitSize_;
     253              : 
     254            0 :         CHK_RET(RunCurrentDeterministicReduceScatter(
     255              :             opType, curInputPtr, curOutputPtr, strideCount * unitSize_, curSize, dataType));
     256              : 
     257            0 :         inputOffset = curSize;
     258            0 :         outputOffset = curSize;
     259              :     }
     260              : 
     261            0 :     return HCCL_SUCCESS;
     262              : }
     263              : 
     264            0 : HcclResult AicpuReduceScatter::RunCurrentDeterministicReduceScatter(
     265              :     HcclReduceOp opType, uint8_t* curInputPtr, uint8_t* curOutputPtr, u64 strideSize, u64 curSize,
     266              :     HcclDataType dataType)
     267              : {
     268            0 :     std::vector<Slice> slices = PrepareMeshSlice(curSize, rankNum_);
     269            0 :     std::vector<uint32_t> srcRankOrder;
     270            0 :     std::vector<uint32_t> dstRankOrder;
     271            0 :     for (uint32_t i = 1; i <= rankNum_ - 1; i++) {
     272            0 :         srcRankOrder.push_back((rankId_ + rankNum_ - i) % rankNum_);
     273            0 :         dstRankOrder.push_back((rankId_ + i) % rankNum_);
     274            0 :         HCCL_DEBUG("SrcRank:%u dstRank:%u", (rankId_ + rankNum_ - i) % rankNum_, (rankId_ + i) % rankNum_);
     275              :     }
     276              :     // 1. 片内send->recv
     277            0 :     AicpuDispatcher::CopyData(
     278            0 :         rankId_, static_cast<void*>(curInputPtr + rankId_ * strideSize), curOutputPtr, curSize, dataType,
     279              :         HCCL_REDUCE_RESERVED, rankId_);
     280            0 :     for (uint32_t round = 0; round < rankNum_ - 1; round++) {
     281              :         // 2. 片内send->win
     282            0 :         for (size_t i = 0; i < slices.size(); i++) {
     283            0 :             uint32_t idx = (round + i) % (rankNum_ - 1);
     284            0 :             u64 sendOff = dstRankOrder[idx] * strideSize + slices[i].offset;
     285            0 :             HCCL_DEBUG(
     286              :                 "Cpy send to win, dstRank:%u, srcOffset:%lu, dstOffset:%lu, size:%lu", dstRankOrder[idx], sendOff,
     287              :                 slices[i].offset, slices[i].size);
     288            0 :             CHK_RET(TaskOrchestrator::SelfCpySnd2Win(
     289              :                 curInputPtr, slices[i].size, sendOff, slices[i].offset, HCCL_REDUCE_RESERVED, dataType));
     290              :         }
     291              :         // 3. 前同步
     292            0 :         CHK_RET(TaskOrchestrator::DoPreSync());
     293              :         // 4. 跨片读 inline reduce
     294            0 :         for (size_t i = 0; i < slices.size(); i++) {
     295            0 :             uint32_t idx = (round + i) % (rankNum_ - 1);
     296            0 :             HCCL_DEBUG(
     297              :                 "Ipc read win to rcv, srcRank:%u, srcOffset:%lu, dstOffset:%lu, size:%lu", srcRankOrder[idx],
     298              :                 slices[i].offset, slices[i].offset, slices[i].size);
     299            0 :             CHK_RET(TaskOrchestrator::IpcCpyWin2RcvP2P(
     300              :                 curOutputPtr, srcRankOrder[idx], slices[i].size, slices[i].offset, slices[i].offset, opType, dataType));
     301              :         }
     302              :         // 5. 后同步
     303            0 :         CHK_RET(TaskOrchestrator::DoPostSync());
     304              :     }
     305            0 :     CHK_RET(TaskOrchestrator::LaunchTasks());
     306            0 :     return HCCL_SUCCESS;
     307            0 : }
     308              : 
     309           28 : HcclResult AicpuReduceScatter::GenRingTask(
     310              :     HcclReduceOp opType, u64 sndAddr, u64 rcvAddr, u64 curSize, u64 scatterSize, HcclDataType dataType,
     311              :     uint32_t streamId, bool isClockwise, uint32_t step) const
     312              : {
     313           28 :     const u64 winIn = ctx_->rankInfo[rankId_].window + (isClockwise ? 0U : ctx_->windowSize / RING_NUM);
     314           28 :     const u64 winOut = ctx_->rankInfo[rankId_].windowOut + (isClockwise ? 0U : ctx_->windowSize / RING_NUM);
     315           28 :     const uint32_t preRankId = isClockwise ? (rankId_ + rankNum_ - 1U) % rankNum_ : (rankId_ + 1) % rankNum_;
     316           28 :     const uint32_t postRankId = isClockwise ? (rankId_ + 1) % rankNum_ : (rankId_ + rankNum_ - 1U) % rankNum_;
     317           28 :     const u64 preWinIn = ctx_->rankInfo[preRankId].window + (isClockwise ? 0U : ctx_->windowSize / RING_NUM);
     318           28 :     const u64 preWinOut = ctx_->rankInfo[preRankId].windowOut + (isClockwise ? 0U : ctx_->windowSize / RING_NUM);
     319           28 :     const bool evenStep = (step % 2U == 0U); // 2: 环上winIn winOut轮流接收, 奇数轮in->out, 偶数轮out->in
     320              : 
     321           28 :     HcclResult ret = HCCL_SUCCESS;
     322           28 :     if (step == 1U) { // 首轮send->winIn winOut
     323            4 :         ret = AicpuDispatcher::CopyData(streamId, sndAddr, winIn, curSize, dataType, HCCL_REDUCE_RESERVED, rankId_);
     324            4 :         CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u send to clock winIn failed", turn_, step), ret);
     325              : 
     326            8 :         ret = AicpuDispatcher::CopyData(
     327            4 :             streamId, sndAddr + scatterSize, winOut, curSize, dataType, HCCL_REDUCE_RESERVED, rankId_);
     328            4 :         CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u send to clock winOut failed", turn_, step), ret);
     329              :     } else {
     330           24 :         ret = AicpuDispatcher::CopyData(
     331           24 :             streamId, sndAddr, evenStep ? winIn : winOut, curSize, dataType, HCCL_REDUCE_RESERVED, rankId_);
     332           24 :         CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u send to clock winOut failed", turn_, step), ret);
     333              :     }
     334              :     // 片间同步 notify后卡 wait前卡
     335           28 :     ret = AicpuDispatcher::SignalRecord(streamId, postRankId, AicpuDispatcher::IPC, AicpuDispatcher::PRE_SYNC);
     336           28 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u notify post rank failed", turn_, step), ret);
     337              : 
     338           28 :     ret = AicpuDispatcher::SignalWait(streamId, preRankId, AicpuDispatcher::IPC, AicpuDispatcher::PRE_SYNC);
     339           28 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u wait pre rank failed", turn_, step), ret);
     340              : 
     341              :     // 片间memcpy 前卡window->window
     342           28 :     ret = AicpuDispatcher::CopyData(
     343              :         streamId, evenStep ? preWinOut : preWinIn, evenStep ? winIn : winOut, curSize, dataType, opType, preRankId);
     344           28 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u cpy pre window failed", turn_, step), ret);
     345           28 :     if (step == rankNum_ - 1U) { // 最后一轮 win输出至recv
     346            4 :         ret = AicpuDispatcher::CopyData(
     347            4 :             streamId, evenStep ? winIn : winOut, rcvAddr, curSize, dataType, HCCL_REDUCE_RESERVED, rankId_);
     348            4 :         CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u window to recv failed", turn_, step), ret);
     349              :     }
     350           28 :     ret = AicpuDispatcher::SignalRecord(streamId, preRankId, AicpuDispatcher::IPC, AicpuDispatcher::POST_SYNC);
     351           28 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u notify pre rank failed", turn_, step), ret);
     352              :     // 片间同步 notify前卡 wait后卡
     353           28 :     ret = AicpuDispatcher::SignalWait(streamId, postRankId, AicpuDispatcher::IPC, AicpuDispatcher::POST_SYNC);
     354           28 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u wait post rank failed", turn_, step), ret);
     355           28 :     return HCCL_SUCCESS;
     356              : }
     357              : 
     358            2 : HcclResult AicpuReduceScatter::RunDoubleRingReduceScatter(
     359              :     HcclReduceOp opType, u64 sendBuffer, u64 recvBuffer, u64 dataCount, HcclDataType dataType) const
     360              : {
     361            2 :     const u64 scatterSize = dataCount / rankNum_ * unitSize_;
     362            2 :     if (scatterSize > ctx_->windowSize / RING_NUM) {
     363            0 :         HCCL_INFO("Tile scatter size %lu max less than window size %lu/RING_NUM", scatterSize, ctx_->windowSize);
     364              :     }
     365              :     thread_local static u64 sndAddr[RING_NUM] = {0UL};
     366              :     thread_local static u64 rcvAddr[RING_NUM] = {0UL};
     367            2 :     if (turn_ == 0U) { // 首个tile时初始化snd rcv地址
     368            1 :         sndAddr[0] = sendBuffer;
     369            1 :         rcvAddr[0] = recvBuffer;
     370            1 :         rcvAddr[1] = recvBuffer + ctx_->totalCnt * unitSize_ / rankNum_;
     371              :     }
     372            2 :     sndAddr[1] = sndAddr[0] + 2U * scatterSize + scatterSize; // 2 首轮需要同时输出到winIn和winOut
     373              : 
     374            2 :     HCCL_INFO(
     375              :         "DR reducescatter snd addr %p %p, rcv addr %p %p, size %lu", sndAddr[0], sndAddr[1], rcvAddr[0], rcvAddr[1],
     376              :         scatterSize);
     377            2 :     uint32_t mainStream = rankId_;
     378            2 :     uint32_t subStream = (rankId_ + 1U) % rankNum_;
     379            2 :     HcclResult ret = HCCL_SUCCESS;
     380              : 
     381            2 :     u64 maxCountPerLoop = ctx_->windowSize / RING_NUM / unitSize_; // 中转内存单次最多能够接受的output count
     382            2 :     u64 countLeft = dataCount / rankNum_;
     383            2 :     bool isWindowFirst = true;
     384            2 :     bool isWindowLast = false;
     385              :     // windowSize循环
     386            2 :     u32 loopIdx = 0;
     387            4 :     while (countLeft > 0) {
     388            2 :         u64 curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
     389            2 :         u64 curSize = curCount * unitSize_; // 单位 byte
     390              : 
     391            2 :         HCCL_DEBUG(
     392              :             "DR reducescatter: loop %u, snd addr[%p %p], rcv addr[%p %p], curCount[%llu], curSize[%llu]", loopIdx++,
     393              :             sndAddr[0], sndAddr[1], rcvAddr[0], rcvAddr[1], curCount, curSize);
     394              : 
     395            2 :         sndAddr[1] -= curSize; // 逆时针输入在执行前向上偏移
     396            2 :         rcvAddr[1] -= curSize; // 逆时针输出在执行前向上偏移
     397              : 
     398            2 :         isWindowLast = ((countLeft - curCount) == 0);
     399              : 
     400            2 :         u64 stepSndAddrClockwise = sndAddr[0];
     401            2 :         u64 stepSndAddrAnticlockwise = sndAddr[1];
     402           16 :         for (uint32_t step = 1U; step <= rankNum_ - 1U; step++) {
     403           14 :             if (isWindowFirst) {
     404              :                 // ccore wait
     405           14 :                 u64 waitAddr = ctx_->workSpaceAddr + ctx_->notifyOff + offsetof(AivAicpuOpParam, sendCnt);
     406           28 :                 ret = AicpuDispatcher::AddCcoreWait(
     407           14 :                     mainStream, waitAddr, turn_ * (rankNum_ - 1U) + step,
     408           14 :                     (turn_ + 1U >= ctx_->totalTurnCnt) && (step == rankNum_ - 1U));
     409           14 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u add ccore wait failed", turn_, step), ret);
     410              :             }
     411              : 
     412              :             // 主->从
     413           14 :             CHK_RET(AicpuDispatcher::SignalRecord(
     414              :                 mainStream, subStream, AicpuDispatcher::NO_IPC, AicpuDispatcher::PRE_SYNC));
     415           14 :             CHK_RET(
     416              :                 AicpuDispatcher::SignalWait(subStream, subStream, AicpuDispatcher::NO_IPC, AicpuDispatcher::PRE_SYNC));
     417              : 
     418              :             // 顺时针环
     419           14 :             CHK_RET(GenRingTask(
     420              :                 opType, stepSndAddrClockwise, rcvAddr[0], curSize, scatterSize, dataType, mainStream, true, step));
     421              :             stepSndAddrClockwise
     422           14 :                 += ((step == 1U) ? 2U * scatterSize * RING_NUM :
     423              :                                    scatterSize * RING_NUM); // 2 首轮需要同时输出到winIn和winOut
     424              : 
     425              :             // 逆时针环
     426           14 :             CHK_RET(GenRingTask(
     427              :                 opType, stepSndAddrAnticlockwise, rcvAddr[1], curSize, scatterSize, dataType, subStream, false, step));
     428              :             stepSndAddrAnticlockwise
     429           14 :                 += ((step == 1U) ? 2U * scatterSize + scatterSize :
     430              :                                    scatterSize * RING_NUM); // 2 首轮需要同时输出到winIn和winOut
     431              : 
     432              :             // 从->主
     433           14 :             CHK_RET(AicpuDispatcher::SignalRecord(
     434              :                 subStream, subStream, AicpuDispatcher::NO_IPC, AicpuDispatcher::POST_SYNC));
     435           14 :             CHK_RET(AicpuDispatcher::SignalWait(
     436              :                 mainStream, subStream, AicpuDispatcher::NO_IPC, AicpuDispatcher::POST_SYNC));
     437           14 :             if (isWindowLast) {
     438           14 :                 ret = TaskOrchestrator::AddBarrier(mainStream, rankId_, rankNum_);
     439           14 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u add barrier failed", turn_, step), ret);
     440              :                 // ccore notify
     441           14 :                 ret = AicpuDispatcher::AddCcoreNotify(mainStream, turn_ * (rankNum_ - 1U) + step);
     442           14 :                 CHK_PRT_RET(
     443              :                     ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u add ccore notify failed", turn_, step), ret);
     444              :             }
     445              :         }
     446            2 :         isWindowFirst = false;
     447            2 :         countLeft -= curCount;
     448            2 :         sndAddr[0] += curSize; // 顺时针输入向下偏移
     449            2 :         rcvAddr[0] += curSize; // 顺时针输出向下偏移
     450              :     }
     451              : 
     452              :     // tile之间回退一个scatterSize再偏移
     453            2 :     sndAddr[0] = sndAddr[0] - scatterSize + rankNum_ * RING_NUM * scatterSize;
     454              : 
     455            2 :     ret = TaskOrchestrator::LaunchTasks();
     456            2 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Launch tasks failed"), ret);
     457            2 :     return HCCL_SUCCESS;
     458              : }
     459              : 
     460            2 : HcclResult AicpuReduceScatter::RunSwitchReduceScatter(
     461              :     HcclReduceOp opType, u64 sendBuffer, u64 recvBuffer, u64 dataCount, HcclDataType dataType) const
     462              : {
     463            2 :     const u64 scatterSize = dataCount / rankNum_ * unitSize_;
     464            2 :     if (scatterSize > ctx_->windowSize) {
     465            0 :         HCCL_INFO("Tile scatter size %lu max less than window size %lu", scatterSize, ctx_->windowSize);
     466              :     }
     467              :     thread_local static u64 sndAddr = 0UL;
     468              :     thread_local static u64 rcvAddr = 0UL;
     469            2 :     if (turn_ == 0U) { // 首个tile时初始化snd rcv地址
     470            1 :         sndAddr = sendBuffer;
     471            1 :         rcvAddr = recvBuffer;
     472              :     }
     473            2 :     uint32_t mainStream = rankId_;
     474            2 :     HCCL_INFO("SW reducescatter snd addr %p, rcv addr %p, size %lu", sndAddr, rcvAddr, scatterSize);
     475              : 
     476            2 :     HcclResult ret = HCCL_SUCCESS;
     477            2 :     u64 maxCountPerLoop = ctx_->windowSize / unitSize_; // 中转内存单次最多能够接受的output count
     478            2 :     u64 countLeft = dataCount / rankNum_;
     479            2 :     bool isWindowFirst = true;
     480            2 :     bool isWindowLast = false;
     481              :     // windowSize循环
     482            4 :     while (countLeft > 0) {
     483            2 :         u64 curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
     484            2 :         u64 curSize = curCount * unitSize_; // 单位 byte
     485              : 
     486            2 :         isWindowLast = ((countLeft - curCount) == 0);
     487              : 
     488            2 :         u64 stepSndAddr = sndAddr;
     489           18 :         for (uint32_t step = 1U; step <= rankNum_; step++) {
     490           16 :             uint32_t preRankId = (rankId_ + rankNum_ - step) % rankNum_;
     491           16 :             uint32_t postRankId = (rankId_ + step) % rankNum_;
     492           16 :             if (isWindowFirst) {
     493              :                 // ccore wait
     494           16 :                 u64 waitAddr = ctx_->workSpaceAddr + ctx_->notifyOff + offsetof(AivAicpuOpParam, sendCnt);
     495           32 :                 ret = AicpuDispatcher::AddCcoreWait(
     496           16 :                     mainStream, waitAddr, turn_ * rankNum_ + step,
     497           16 :                     (turn_ + 1u >= ctx_->totalTurnCnt) && (step == rankNum_));
     498           16 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u add ccore wait failed", turn_, step), ret);
     499              :             }
     500              : 
     501           16 :             if (step != rankNum_) {
     502              :                 // 片间同步 notify前卡 wait后卡
     503           14 :                 ret = AicpuDispatcher::SignalRecord(
     504              :                     mainStream, preRankId, AicpuDispatcher::IPC, AicpuDispatcher::PRE_SYNC);
     505           14 :                 CHK_PRT_RET(
     506              :                     ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u notify pre rank failed", turn_, step), ret);
     507              : 
     508           14 :                 ret = AicpuDispatcher::SignalWait(
     509              :                     mainStream, postRankId, AicpuDispatcher::IPC, AicpuDispatcher::PRE_SYNC);
     510           14 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u wait post rank failed", turn_, step), ret);
     511              : 
     512              :                 // 片间memcpy snd->后序卡win 首轮采用覆盖
     513           14 :                 ret = AicpuDispatcher::CopyData(
     514           14 :                     mainStream, stepSndAddr, ctx_->rankInfo[postRankId].window, curSize, dataType,
     515              :                     step == 1U ? HCCL_REDUCE_RESERVED : opType, postRankId);
     516           14 :                 CHK_PRT_RET(
     517              :                     ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u cpy snd to post win failed", turn_, step), ret);
     518           14 :                 stepSndAddr += scatterSize;
     519              : 
     520              :                 // 片间同步 notify后卡 wait前卡
     521           14 :                 ret = AicpuDispatcher::SignalRecord(
     522              :                     mainStream, postRankId, AicpuDispatcher::IPC, AicpuDispatcher::POST_SYNC);
     523           14 :                 CHK_PRT_RET(
     524              :                     ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u notify post rank failed", turn_, step), ret);
     525              : 
     526           14 :                 ret = AicpuDispatcher::SignalWait(
     527              :                     mainStream, preRankId, AicpuDispatcher::IPC, AicpuDispatcher::POST_SYNC);
     528           14 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u wait pre rank failed", turn_, step), ret);
     529              :             } else { // 最后一轮仅作本卡内拷贝
     530              :                 // snd->recv
     531            4 :                 ret = AicpuDispatcher::CopyData(
     532            2 :                     mainStream, stepSndAddr, rcvAddr, curSize, dataType, HCCL_REDUCE_RESERVED, rankId_);
     533            2 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u cpy snd to rcv failed", turn_, step), ret);
     534            2 :                 stepSndAddr += scatterSize;
     535              : 
     536              :                 // win->recv
     537            4 :                 ret = AicpuDispatcher::CopyData(
     538            2 :                     mainStream, ctx_->rankInfo[rankId_].window, rcvAddr, curSize, dataType, opType, rankId_);
     539            2 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u cpy win to rcv failed", turn_, step), ret);
     540              :             }
     541           16 :             if (isWindowLast) {
     542           16 :                 ret = TaskOrchestrator::AddBarrier(mainStream, rankId_, rankNum_);
     543           16 :                 CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u add barrier failed", turn_, step), ret);
     544              : 
     545              :                 // ccore notify
     546           16 :                 ret = AicpuDispatcher::AddCcoreNotify(mainStream, turn_ * rankNum_ + step);
     547           16 :                 CHK_PRT_RET(
     548              :                     ret != HCCL_SUCCESS, HCCL_ERROR("Turn %u step %u add ccore notify failed", turn_, step), ret);
     549              :             }
     550              :         }
     551            2 :         isWindowFirst = false;
     552            2 :         countLeft -= curCount;
     553            2 :         sndAddr += curSize;
     554            2 :         rcvAddr += curSize;
     555              :     }
     556              : 
     557              :     // 回退一个scatterSize再偏移
     558            2 :     sndAddr = sndAddr - scatterSize + rankNum_ * scatterSize;
     559              : 
     560            2 :     ret = TaskOrchestrator::LaunchTasks();
     561            2 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("Launch tasks failed"), ret);
     562            2 :     return HCCL_SUCCESS;
     563              : }
        

Generated by: LCOV version 2.0-1