LCOV - code coverage report
Current view: top level - src/api_check - kernel_vec_reduce_other_check.cpp (source / functions) Coverage Total Hit
Test: coverage.info_filtered Lines: 60.2 % 176 106
Test Date: 2026-07-27 14:41:20 Functions: 66.7 % 18 12

            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              : /*!
      12              :  * \file kernel_vec_reduce_other_check.cpp
      13              :  * \brief
      14              :  */
      15              : 
      16              : #include "kernel_check_params.h"
      17              : #include "model/model_factory_mask.h"
      18              : #include "kernel_vec_reduce_other_check.h"
      19              : 
      20              : namespace AscendC {
      21              : namespace check {
      22              : 
      23           40 : bool TikcppVecReduceOtherCheck::CheckWholeReduceDtypeBytes(const std::string& errMsg)
      24              : {
      25           40 :     uint32_t dstDtypeBytes = param_.dstDtypeBytes;
      26           40 :     uint32_t srcDtypeBytes = param_.src0DtypeBytes;
      27              : #if defined(__NPU_ARCH__) && ((__NPU_ARCH__ == 3510) || (__NPU_ARCH__ == 5102))
      28              :     // WholeReduceSum Support type promotion: dst byte size can be 2x src byte size
      29              :     // (e.g. int32_t/int16_t, uint32_t/uint16_t)
      30              :     if (apiName == "WholeReduceSum") {
      31              :         constexpr uint32_t kMaxDstSrcByteRatio = 2;
      32              :         if ((dstDtypeBytes != srcDtypeBytes) && (dstDtypeBytes != srcDtypeBytes * kMaxDstSrcByteRatio)) {
      33              :             CHECK_LOG_ERROR(
      34              :                 "%s, "
      35              :                 "ReduceSum need dst data type (%u) should be same or 2x of src type (%u)",
      36              :                 errMsg.c_str(), dstDtypeBytes, srcDtypeBytes);
      37              :             return false;
      38              :         }
      39              :     } else
      40              : #endif
      41              :     {
      42           40 :         if (dstDtypeBytes != srcDtypeBytes) {
      43            4 :             CHECK_LOG_ERROR(
      44              :                 "%s, "
      45              :                 "Reduce need dst data type (%u),dst src type (%u), should be same",
      46              :                 errMsg.c_str(), dstDtypeBytes, srcDtypeBytes);
      47            4 :             return false;
      48              :         }
      49              :     }
      50           36 :     return true;
      51              : }
      52              : 
      53           28 : bool TikcppVecReduceOtherCheck::CheckWholeReduceDstSize()
      54              : {
      55           28 :     uint32_t needCount = (param_.dstRepeatStride != 0) ? param_.repeatTimes * param_.dstRepeatStride : 1;
      56           28 :     uint64_t needSize = static_cast<uint64_t>(needCount * param_.dstDtypeBytes);
      57          112 :     ASCENDC_CHECK(CheckTensorSizeOverflow(needSize, param_.dstSize, "dstLocal", apiName.c_str()));
      58           28 :     return true;
      59              : }
      60              : 
      61            0 : static bool CheckTensorWhlSumOverflowLowCounter(
      62              :     std::vector<uint64_t>& maskArray, const VecReduceApiParams& param, const uint64_t unit,
      63              :     const std::string& tensorName, const std::string& apiName)
      64              : {
      65            0 :     uint32_t oneRepeatNum = ONE_REPEAT_BYTE_SIZE / param.dstDtypeBytes;          // when counter mode, always full mask
      66            0 :     uint64_t elementNum = (maskArray.size() == 1) ? maskArray[0] : maskArray[1]; // maskLow means element num
      67            0 :     int32_t repeatTimes = (elementNum + oneRepeatNum - 1) / oneRepeatNum;
      68            0 :     uint32_t needSize = (repeatTimes - 1) * param.dstRepeatStride * unit + unit;
      69            0 :     ASCENDC_CHECK(CheckTensorSizeOverflow(needSize, param.dstSize, tensorName, apiName, ModeType::COUNTER_MODE));
      70            0 :     return true;
      71              : }
      72              : 
      73            8 : static bool CheckTensorWhlSumOverflowLowNorm(
      74              :     const VecReduceApiParams& param, const uint64_t unit, const std::string& tensorName, const std::string& apiName)
      75              : {
      76            8 :     uint32_t needSize = (param.repeatTimes - 1) * param.dstRepeatStride * unit + unit;
      77            8 :     ASCENDC_CHECK(CheckTensorSizeOverflow(needSize, param.dstSize, tensorName, apiName, ModeType::NORM_MODE));
      78            8 :     return true;
      79              : }
      80              : 
      81            8 : bool TikcppVecReduceOtherCheck::CheckWholeReduceDstSize(
      82              :     std::vector<uint64_t>& maskArray, const uint64_t unit, const std::string& tensorName)
      83              : {
      84            8 :     if (ModelFactoryGetMaskMode() == 1) { // counter mode
      85            0 :         return CheckTensorWhlSumOverflowLowCounter(maskArray, param_, unit, tensorName, apiName);
      86              :     }
      87            8 :     return CheckTensorWhlSumOverflowLowNorm(param_, unit, tensorName, apiName);
      88              : }
      89              : 
      90            0 : static uint64_t CalculatePairVecMaxOffset(
      91              :     const uint64_t repeatTimes, const uint64_t blkStride, const uint64_t repStride, const uint64_t maskLen,
      92              :     const uint64_t blockLen, uint32_t unit, const uint32_t dtypeBytes)
      93              : {
      94            0 :     if (repeatTimes == 0) {
      95            0 :         return 0;
      96              :     }
      97            0 :     ASSERT(blockLen != 0);
      98            0 :     uint64_t maskNum = maskLen / 2;                      // every 2 src get 1 dst
      99            0 :     uint64_t blkNumLastRep = DivCeil(maskNum, blockLen); // last repeat needs x blocks for maskLen elements
     100            0 :     uint64_t eleNumLastBlk = ((maskNum % blockLen) != 0) ? (maskNum % blockLen) : blockLen;
     101            0 :     uint64_t maxOffset = (repeatTimes - 1) * unit * repStride +
     102            0 :                          (blkNumLastRep - 1) * blkStride * blockLen * dtypeBytes + eleNumLastBlk * dtypeBytes;
     103            0 :     return maxOffset;
     104              : }
     105              : 
     106            0 : static uint64_t CalculatePairNeededTensorSize(
     107              :     std::vector<uint64_t>& maskArray, const uint32_t dtypeBytes, const uint64_t repeatTimes, const uint64_t blkStride,
     108              :     const uint64_t repStride, uint32_t unit)
     109              : {
     110            0 :     uint64_t maskVal = (maskArray.size() == 1) ? maskArray[0] : GetMaskLength(maskArray, dtypeBytes);
     111            0 :     ASSERT(dtypeBytes != 0);
     112            0 :     uint64_t eleNumPerBlock = static_cast<uint64_t>(PlatFormParams::ONE_BLK_SIZE) / dtypeBytes;
     113              :     uint64_t maxOffset =
     114            0 :         CalculatePairVecMaxOffset(repeatTimes, blkStride, repStride, maskVal, eleNumPerBlock, unit, dtypeBytes);
     115            0 :     return maxOffset;
     116              : }
     117              : 
     118            0 : static bool CheckTensorPairOverflowLowCounter(
     119              :     std::vector<uint64_t>& maskArray, const VecReduceApiParams& param, const std::string& tensorName,
     120              :     const std::string& apiName)
     121              : {
     122            0 :     std::vector<uint64_t> mainMaskArray = {0};
     123            0 :     std::vector<uint64_t> tailMaskArray = {0};
     124            0 :     uint64_t mainRepeatTimes = 0;
     125            0 :     uint64_t tailRepeatTimes = 0;
     126            0 :     CounterSplitMainTail(
     127            0 :         maskArray, param.dstDtypeBytes, mainRepeatTimes, tailRepeatTimes, mainMaskArray, tailMaskArray);
     128              :     uint64_t maskVal =
     129            0 :         (mainMaskArray.size() == 1) ? mainMaskArray[0] : GetMaskLength(mainMaskArray, param.dstDtypeBytes);
     130            0 :     uint32_t unit = maskVal / 2 * param.dstDtypeBytes;
     131            0 :     uint64_t mainBlkSize = CalculatePairNeededTensorSize(
     132            0 :         mainMaskArray, param.dstDtypeBytes, mainRepeatTimes, DEFAULT_BLK_STRIDE, param.dstRepeatStride, unit);
     133            0 :     uint64_t maxOffset = mainBlkSize;
     134            0 :     if (tailRepeatTimes > 0) { // calculate tail block from the last repStride in main block
     135            0 :         uint64_t tailRepeatStart = mainRepeatTimes * param.dstRepeatStride * unit;
     136            0 :         uint64_t tailBlkSize = CalculatePairNeededTensorSize(
     137            0 :             tailMaskArray, param.dstDtypeBytes, tailRepeatTimes, DEFAULT_BLK_STRIDE, param.dstRepeatStride, unit);
     138            0 :         maxOffset = std::max(mainBlkSize, tailRepeatStart + tailBlkSize);
     139              :     }
     140            0 :     ASCENDC_CHECK(CheckTensorSizeOverflow(maxOffset, param.dstSize, tensorName, apiName, ModeType::COUNTER_MODE));
     141            0 :     return true;
     142            0 : }
     143              : 
     144           12 : static bool CheckTensorPairOverflowLowNorm(
     145              :     std::vector<uint64_t>& maskArray, const VecReduceApiParams& param, const std::string& tensorName,
     146              :     const std::string& apiName)
     147              : {
     148           12 :     uint64_t maskVal = (maskArray.size() == 1) ? maskArray[0] : GetMaskLength(maskArray, param.dstDtypeBytes);
     149           12 :     uint32_t unit = maskVal / 2 * param.dstDtypeBytes;
     150           12 :     uint32_t lastRepeatSize = maskVal / 2;
     151           12 :     uint32_t needSize = (param.repeatTimes - 1) * param.dstRepeatStride * unit + lastRepeatSize * param.dstDtypeBytes;
     152           12 :     ASCENDC_CHECK(CheckTensorSizeOverflow(needSize, param.dstSize, tensorName, apiName, ModeType::NORM_MODE));
     153            4 :     return true;
     154              : }
     155              : 
     156           12 : bool TikcppVecReduceOtherCheck::CheckPairReduceDstSize(std::vector<uint64_t>& maskArray, const std::string& tensorName)
     157              : {
     158           12 :     if (ModelFactoryGetMaskMode() == 1) { // counter mode
     159            0 :         return CheckTensorPairOverflowLowCounter(maskArray, param_, tensorName, apiName);
     160              :     }
     161           12 :     return CheckTensorPairOverflowLowNorm(maskArray, param_, tensorName, apiName);
     162              : }
     163              : 
     164              : // this api do not support counter mode due to param elemsInOneRepeat is only for norm mode
     165            0 : bool TikcppVecReduceOtherCheck::CheckRepeatReduceDstSize()
     166              : {
     167              :     // in RepeatReduceSum, dstRepStride is in unit of element
     168              :     // 1 repeatTimes: 1 element      > 1 repeatTimes: 1 element + dstRepStride jump
     169            0 :     uint32_t expectedSize = ((param_.repeatTimes - 1) * param_.dstRepeatStride + 1) * param_.dstDtypeBytes;
     170            0 :     ASCENDC_CHECK(CheckTensorSizeOverflow(expectedSize, param_.dstSize, "dstLocal", apiName.c_str()));
     171            0 :     return true;
     172              : }
     173              : 
     174           60 : bool TikcppVecReduceOtherCheck::CheckAddrAlign()
     175              : {
     176           60 :     uint8_t alignByte = ONE_BLK_SIZE;
     177           60 :     bool dstRes = true;
     178           60 :     bool src0Res = true;
     179           60 :     if ((apiName == "BlockReduceMax") || (apiName == "BlockReduceMin") || (apiName == "BlockReduceSum")) {
     180           20 :         if (param_.dstDtypeBytes == sizeof(half)) {
     181           20 :             alignByte = 16; // half type align Bytes is 16B
     182              :         }
     183           40 :         dstRes = CheckTensorAddrAlign(param_.dstAddr, param_.dstPos, alignByte, "dst");
     184           40 :         src0Res = CheckTensorAddrAlign(param_.src0Addr, param_.src0Pos, ONE_BLK_SIZE, "src0");
     185           20 :         return dstRes && src0Res;
     186              :     }
     187           40 :     if (apiName == "PairReduceSum") {
     188            8 :         dstRes = CheckTensorAddrAlign(param_.dstAddr, param_.dstPos, ONE_BLK_SIZE, "dst");
     189            8 :         src0Res = CheckTensorAddrAlign(param_.src0Addr, param_.src0Pos, ONE_BLK_SIZE, "src0");
     190            4 :         return dstRes && src0Res;
     191              :     }
     192           36 :     alignByte = 4; // float type align Bytes is 4B
     193           36 :     if (param_.dstDtypeBytes == sizeof(half)) {
     194           36 :         alignByte = 2; // half type align Bytes is 2B
     195              :     }
     196           72 :     dstRes = CheckTensorAddrAlign(param_.dstAddr, param_.dstPos, alignByte, "dst");
     197           36 :     return dstRes;
     198              : }
     199              : 
     200              : // calculate max extent, aka the offset of the end of all effective element
     201              : // maskLen: each repeat calculate the first maskLen elements
     202              : // blockLen: element num per block
     203              : // return: in unit of element
     204           20 : static uint64_t CalculateByteVectorMaxOffset(
     205              :     const uint64_t repeatTimes, const uint64_t blkStride, const uint64_t repStride, const uint64_t maskLen,
     206              :     const uint64_t blockLen)
     207              : {
     208           20 :     if (repeatTimes == 0) {
     209            0 :         return 0;
     210              :     }
     211           20 :     ASSERT(blockLen != 0);
     212           20 :     uint64_t maskNum = (maskLen + blockLen - 1) / blockLen;       // one block get one dst elements
     213           20 :     uint64_t blkNumLastRep = (maskNum + blockLen - 1) / blockLen; // last repeat needs x blocks for maskNum elements
     214           20 :     uint64_t eleNumLastBlk = ((maskNum % blockLen) != 0) ? (maskNum % blockLen) : blockLen;
     215           20 :     uint64_t maxOffset =
     216           20 :         ((repeatTimes - 1) * repStride / 32 + (blkNumLastRep - 1) * blkStride) * blockLen + eleNumLastBlk;
     217           20 :     return maxOffset;
     218              : }
     219              : 
     220              : // Given repeatTimes and stride etc, to return total buffersize needed in unit of Bytes
     221           20 : static uint64_t CalculateNeededByteTensorSize(
     222              :     std::vector<uint64_t>& maskArray, const uint32_t dtypeBytes, const uint64_t repeatTimes, const uint64_t blkStride,
     223              :     const uint64_t repStride)
     224              : {
     225           20 :     uint64_t maskVal = (maskArray.size() == 1) ? maskArray[0] : GetMaskLength(maskArray, dtypeBytes);
     226           20 :     ASSERT(dtypeBytes != 0);
     227           20 :     uint64_t eleNumPerBlock = static_cast<uint64_t>(PlatFormParams::ONE_BLK_SIZE) / dtypeBytes;
     228           20 :     uint64_t maxOffset = CalculateByteVectorMaxOffset(repeatTimes, blkStride, repStride, maskVal, eleNumPerBlock);
     229           20 :     maxOffset = maxOffset * dtypeBytes;
     230           20 :     return maxOffset;
     231              : }
     232              : 
     233            0 : static bool CheckTensorByteOverflowLowCounter(
     234              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName,
     235              :     const std::string& apiName)
     236              : {
     237            0 :     std::vector<uint64_t> mainMaskArray = {0};
     238            0 :     std::vector<uint64_t> tailMaskArray = {0};
     239            0 :     uint64_t mainRepeatTimes = 0;
     240            0 :     uint64_t tailRepeatTimes = 0;
     241            0 :     CounterSplitMainTail(maskArray, params.dtypeSize, mainRepeatTimes, tailRepeatTimes, mainMaskArray, tailMaskArray);
     242              :     // when counter mode, repeatTimes given by user is not used
     243              :     // Need to compare: endpoint of mainBlock VS endpoint of tailBlock
     244              :     // Especially scenes where blkStride is much larger than repStride. mainBlock endpoint will be larger!!
     245            0 :     uint64_t mainBlkSize = CalculateNeededByteTensorSize(
     246            0 :         mainMaskArray, params.dtypeSize, mainRepeatTimes, params.blkStride, params.repStride);
     247            0 :     uint64_t maxOffset = mainBlkSize;
     248            0 :     if (tailRepeatTimes > 0) { // calculate tail block from the last repStride in main block
     249            0 :         uint64_t tailRepeatStart = mainRepeatTimes * params.repStride / 32 * ONE_BLK_SIZE / 2;
     250            0 :         uint64_t tailBlkSize = CalculateNeededByteTensorSize(
     251            0 :             tailMaskArray, params.dtypeSize, tailRepeatTimes, params.blkStride,
     252            0 :             params.repStride); // the unit of repStride is Byte
     253            0 :         maxOffset = std::max(mainBlkSize, tailRepeatStart + tailBlkSize);
     254              :     }
     255            0 :     ASCENDC_CHECK(CheckTensorSizeOverflow(maxOffset, params.bufferSize, tensorName, apiName, ModeType::COUNTER_MODE));
     256            0 :     return true;
     257            0 : }
     258              : 
     259              : // in normal mode, check whether the data calculated in cmd exceed the tensor size
     260           20 : static bool CheckTensorByteOverflowLowNorm(
     261              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName,
     262              :     const std::string& apiName)
     263              : {
     264           40 :     uint64_t maxOffset = CalculateNeededByteTensorSize(
     265           20 :         maskArray, params.dtypeSize, params.repeatTimes, params.blkStride, params.repStride);
     266           20 :     ASCENDC_CHECK(CheckTensorSizeOverflow(maxOffset, params.bufferSize, tensorName, apiName, ModeType::NORM_MODE));
     267           20 :     return true;
     268              : }
     269              : 
     270              : // the unit of dstRepStride is Byte
     271           20 : bool TikcppVecReduceOtherCheck::CheckTensorByteOverflowLow(
     272              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName)
     273              : {
     274           20 :     if (ModelFactoryGetMaskMode() == 1) { // counter mode
     275            0 :         return CheckTensorByteOverflowLowCounter(maskArray, params, tensorName, apiName);
     276              :     }
     277           20 :     return CheckTensorByteOverflowLowNorm(maskArray, params, tensorName, apiName);
     278              : }
     279              : 
     280           72 : bool TikcppVecReduceOtherCheck::CheckAllLowLevel(std::vector<uint64_t> maskArray)
     281              : {
     282           72 :     uint32_t maxByteLen = std::max(param_.dstDtypeBytes, param_.src0DtypeBytes);
     283           72 :     ASCENDC_CHECK(UpdateMaskArrayAndCheck(maskArray, maxByteLen));
     284              : 
     285           72 :     if ((apiName == "WholeReduceSum")) {
     286           24 :         ASCENDC_CHECK(CheckWholeReduceDtypeBytes("Check Whole Reduce data type"));
     287           16 :         ASCENDC_CHECK(CheckWholeReduceDstSize(maskArray, param_.dstDtypeBytes, "dstLocal"));
     288              :     }
     289              : 
     290           68 :     if ((apiName == "WholeReduceMax") || (apiName == "WholeReduceMin")) {
     291           56 :         ASCENDC_CHECK(CheckWholeReduceDtypeBytes("Check Whole Reduce data type"));
     292           28 :         ASCENDC_CHECK(CheckWholeReduceDstSize());
     293              :     }
     294              : 
     295           68 :     if ((apiName == "BlockReduceSum") || (apiName == "BlockReduceMax") || (apiName == "BlockReduceMin")) {
     296              :         TensorOverflowParams params = {
     297           20 :             param_.dstSize,
     298           20 :             param_.dstDtypeBytes,
     299           20 :             static_cast<uint64_t>(param_.repeatTimes),
     300              :             static_cast<uint64_t>(DEFAULT_BLK_STRIDE),
     301           20 :             static_cast<uint64_t>(param_.dstRepeatStride * param_.dstDtypeBytes * 8),
     302           20 :             false};
     303           40 :         ASCENDC_CHECK(CheckTensorByteOverflowLow(maskArray, params, "dstLocal"));
     304              :     }
     305              : 
     306           68 :     if (apiName == "PairReduceSum") {
     307           24 :         ASCENDC_CHECK(CheckPairReduceDstSize(maskArray, "dstLocal"));
     308              :     }
     309              : 
     310           60 :     if (apiName == "RepeatReduceSum") {
     311            0 :         ASCENDC_CHECK(CheckRepeatReduceDstSize());
     312              :     }
     313              : 
     314           60 :     const std::string supportPos = "VECIN/VECOUT/VECCALC";
     315          180 :     ASCENDC_CHECK(CheckTensorScope(param_.dstLogicPos, static_cast<uint8_t>(HardWareIndex::UB), "dst", supportPos));
     316          180 :     ASCENDC_CHECK(CheckTensorScope(param_.src0LogicPos, static_cast<uint8_t>(HardWareIndex::UB), "src", supportPos));
     317              : 
     318           60 :     ASCENDC_CHECK(CheckAddrAlign());
     319              : 
     320          180 :     ASCENDC_CHECK(CheckBufferSizeOverFlow(
     321              :         param_.dstSize, GlobalParams::Instance().bufferSizeMap.at(param_.dstPos),
     322              :         "check dst tensor buffersize failed"));
     323          180 :     ASCENDC_CHECK(CheckBufferSizeOverFlow(
     324              :         param_.src0Size, GlobalParams::Instance().bufferSizeMap.at(param_.src0Pos),
     325              :         "check src tensor buffersize failed"));
     326              : 
     327              :     TensorOverflowParams params = {
     328           60 :         param_.src0Size,
     329           60 :         param_.src0DtypeBytes,
     330           60 :         static_cast<uint64_t>(param_.repeatTimes),
     331           60 :         static_cast<uint64_t>(param_.src0BlockStride),
     332           60 :         static_cast<uint64_t>(param_.src0RepeatStride),
     333           60 :         false};
     334          180 :     ASCENDC_CHECK(CheckTensorOverflowLow(maskArray, params, "srcLocal"));
     335           60 :     return true;
     336           60 : }
     337              : } // namespace check
     338              : } // namespace AscendC
        

Generated by: LCOV version 2.0-1