LCOV - code coverage report
Current view: top level - src/api_check - kernel_base_check.cpp (source / functions) Coverage Total Hit
Test: coverage.info_filtered Lines: 54.5 % 154 84
Test Date: 2026-07-27 14:41:20 Functions: 77.8 % 18 14

            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_base_check.cpp
      13              :  * \brief
      14              :  */
      15              : #include "kernel_base_check.h"
      16              : #include "kernel_check_params.h"
      17              : #include "kernel_utils.h"
      18              : #include "model/model_factory_mask.h"
      19              : 
      20              : namespace AscendC {
      21              : namespace check {
      22              : constexpr const uint64_t CONST_UINT32_MAX = 0xffffffff;
      23              : 
      24              : // extract total element num in each repeat. Used in normal mode
      25           96 : uint64_t GetMaskLength(std::vector<uint64_t>& maskArray, const uint32_t dtypeSize)
      26              : {
      27           96 :     uint64_t maskLen = 0;
      28           96 :     if (maskArray[static_cast<int32_t>(CommonParams::MASK_HIGH_IDX)] == 0) {
      29              :         // get last element index in mask_low_idx
      30            0 :         for (uint32_t i = 0; i < static_cast<uint32_t>(CommonParams::MASK_MAX_ELE_LEN); ++i) {
      31            0 :             if ((maskArray[static_cast<int32_t>(CommonParams::MASK_LOW_IDX)] & (CONST_MASK_VALUE >> i)) != 0) {
      32            0 :                 maskLen = static_cast<uint64_t>(CommonParams::MASK_MAX_ELE_LEN) - static_cast<uint64_t>(i);
      33            0 :                 break;
      34              :             }
      35              :         }
      36              :     } else {
      37              :         // get last element index in mask_high_idx, then add 64
      38           96 :         for (uint32_t i = 0; i < static_cast<uint32_t>(CommonParams::MASK_MAX_ELE_LEN); ++i) {
      39           96 :             if ((maskArray[static_cast<int32_t>(CommonParams::MASK_HIGH_IDX)] & (CONST_MASK_VALUE >> i)) != 0) {
      40           96 :                 maskLen = static_cast<uint64_t>(CommonParams::MASK_MAX_ELE_LEN) +
      41           96 :                           static_cast<uint64_t>(CommonParams::MASK_MAX_ELE_LEN) - static_cast<uint64_t>(i);
      42           96 :                 break;
      43              :             }
      44              :         }
      45              :     }
      46           96 :     if (dtypeSize >= sizeof(uint32_t)) {
      47            0 :         uint64_t maxElePerRep = DEFAULT_BLOCK_SIZE / dtypeSize;
      48            0 :         maskLen = (maskLen >= maxElePerRep) ? maxElePerRep : maskLen;
      49              :     }
      50           96 :     return maskLen;
      51              : }
      52              : 
      53          556 : bool CheckTensorSizeOverflow(
      54              :     uint64_t expectedSize, uint64_t tensorSize, const std::string& tensorName, const std::string& apiName,
      55              :     const ModeType mode)
      56              : {
      57          556 :     std::string curMode = "";
      58          556 :     if (mode == ModeType::NORM_MODE) {
      59          296 :         curMode = " when in normal mode";
      60          260 :     } else if (mode == ModeType::COUNTER_MODE) {
      61            0 :         curMode = " when in counter mode";
      62              :     }
      63          556 :     ASCENDC_CHECK_AND_LOG(expectedSize <= tensorSize, {
      64              :         CHECK_LOG_ERROR(
      65              :             "Failed to check %s size in %s%s, tensor size "
      66              :             "needs to be at least %lu bytes, while current tensor size is only %lu bytes.",
      67              :             tensorName.c_str(), apiName.c_str(), curMode.c_str(), expectedSize, tensorSize);
      68              :     });
      69          444 :     return true;
      70          556 : }
      71              : 
      72          200 : bool TikcppBaseCheck::CheckTensorOverflowHigh(
      73              :     const uint32_t dtypeSize, const uint64_t bufferSize, const uint32_t calCount, const std::string& tensorName) const
      74              : {
      75          200 :     uint64_t needSize = static_cast<uint64_t>(dtypeSize * calCount);
      76          200 :     if (Int4Setter::Instance().GetInt4()) {
      77            0 :         needSize = static_cast<uint64_t>(calCount / INT4_TWO);
      78            0 :         Int4Setter::Instance().ResetInt4();
      79              :     }
      80          200 :     ASCENDC_CHECK(CheckTensorSizeOverflow(needSize, bufferSize, tensorName, apiName));
      81          136 :     return true;
      82              : }
      83              : 
      84          196 : bool TikcppBaseCheck::UpdateMaskArrayAndCheck(std::vector<uint64_t>& maskArray, const uint32_t maxByteLen) const
      85              : {
      86              :     // do not use mask given by user, use mask value stored in registers
      87          196 :     if (!MaskSetter::Instance().GetMask()) {
      88            0 :         maskArray = {ModelFactoryGetMaskHigh(), ModelFactoryGetMaskLow()};
      89            0 :         CHECK_LOG_INFO(
      90              :             "Due to isSetMask = false, maskArray is changed to maskHigh %lu, maskLow %lu.", ModelFactoryGetMaskHigh(),
      91              :             ModelFactoryGetMaskLow());
      92              :     }
      93          196 :     MaskSetter::Instance().SetMask(true);
      94          196 :     if (maxByteLen >= sizeof(int32_t) && maskArray.size() == 2) { // when size 2 need to update maskHigh
      95              :         // Example: mask[64, 64] but dtype is float, maximum only read 1 64. maskHigh is unused, need to set to 0.
      96            0 :         maskArray[0] = 0; // in counter / norm mode, both maskHigh is in fact 0
      97              :     }
      98          196 :     if (maskArray.size() != 1 && maskArray.size() != 2) { // mask = len 1, mask[2] = len 2
      99            0 :         ASCENDC_CHECK_AND_LOG(
     100              :             false, { CHECK_LOG_ERROR("maskArray size is %lu, which should be 1 or 2.", maskArray.size()); });
     101          196 :     } else if (maskArray.size() == 1) {
     102              :         // when norm mode, update mask value to <= 128 when array size is 1
     103          144 :         if (ModelFactoryGetMaskMode() == 0) {
     104          144 :             uint64_t maxElePerRep = DEFAULT_BLOCK_SIZE / maxByteLen;
     105          144 :             maskArray[0] = std::min(maskArray[0], maxElePerRep);
     106              :         }
     107          144 :         ASCENDC_CHECK_AND_LOG(CheckMaskImm(maskArray[0]), {
     108              :             CHECK_LOG_ERROR(
     109              :                 "When maskArray size is 1, mask value %lu "
     110              :                 "is invalid",
     111              :                 maskArray[0]);
     112              :         });
     113              :     } else {
     114           52 :         ASCENDC_CHECK_AND_LOG(CheckMaskArray(maskArray), {
     115              :             CHECK_LOG_ERROR(
     116              :                 "When maskArray size is 2, maskHigh %lu, "
     117              :                 "maskLow %lu is invalid",
     118              :                 maskArray[0], maskArray[1]);
     119              :         });
     120              :     }
     121          196 :     return true;
     122              : }
     123              : 
     124          916 : bool TikcppBaseCheck::CheckTensorScope(
     125              :     const uint8_t logicPos, const uint8_t expectedPos, const std::string& tensorInfo, const std::string& posInfo) const
     126              : {
     127          916 :     auto& hwNameMap = GlobalParams::Instance().hardwareNameMap;
     128              :     // tensorPos从逻辑位置转换到物理位置
     129          916 :     uint8_t hardPos = static_cast<uint8_t>(GetPhyType(static_cast<TPosition>(logicPos)));
     130          916 :     if (hwNameMap.find(hardPos) == hwNameMap.end() || hwNameMap.find(expectedPos) == hwNameMap.end()) {
     131            0 :         CHECK_LOG_ERROR(
     132              :             "the tensorPos/expectPos hardware pos not found, tensorPos index is %hhu, expectedPos is %hhu.", hardPos,
     133              :             expectedPos);
     134            0 :         return false;
     135              :     }
     136              : 
     137          916 :     ASCENDC_CHECK_AND_LOG(hardPos == expectedPos, {
     138              :         const std::string supportedPos = GetPositionDisplay(static_cast<Hardware>(expectedPos), posInfo);
     139              :         const std::string currentPos = GetPositionDisplay(static_cast<TPosition>(logicPos));
     140              :         CHECK_LOG_ERROR(
     141              :             "Failed to check %s tensor position in %s, "
     142              :             "supported positions are %s, current position is %s.",
     143              :             tensorInfo.c_str(), apiName.c_str(), supportedPos.c_str(), currentPos.c_str());
     144              :     });
     145          832 :     return true;
     146              : }
     147              : 
     148          792 : bool TikcppBaseCheck::CheckBufferSizeOverFlow(
     149              :     const uint64_t localSize, const uint64_t bufferSize, const std::string& errMsg) const
     150              : {
     151          792 :     if (localSize > bufferSize) {
     152            0 :         CHECK_LOG_ERROR(
     153              :             "%s, Allocated buffer size overflow, allocate buffer size is %lu, the limit size is %lu.", errMsg.c_str(),
     154              :             localSize, bufferSize);
     155            0 :         return false;
     156              :     }
     157          792 :     return true;
     158              : }
     159              : 
     160              : // check vector mask input range
     161           52 : bool TikcppBaseCheck::CheckMaskArray(std::vector<uint64_t> maskArray) const
     162              : {
     163              :     // counter mode
     164           52 :     if (ModelFactoryGetMaskMode() == 1) {
     165            0 :         if (maskArray[1] > CONST_UINT32_MAX) { // only use maskLow[0:32] as counter mask. Only give warning!
     166            0 :             CHECK_LOG_WARNING(
     167              :                 "Failed to check mask array in counter mode, maskLow must be in range 0 ~ %lu, current "
     168              :                 "value is %lu",
     169              :                 CONST_UINT32_MAX, maskArray[1]);
     170              :         }
     171            0 :         return true;
     172              :     }
     173              :     // normal mode
     174              : #if defined(__NPU_ARCH__) && (__NPU_ARCH__ == 1001 || __NPU_ARCH__ == 2002)
     175           26 :     ASCENDC_CHECK_AND_LOG(maskArray[0] != 0ULL || maskArray[1] != 0ULL, {
     176              :         CHECK_LOG_ERROR(
     177              :             "During calculation in "
     178              :             "normal mode in Ascend910 / Ascend310p / Ascend610, maskHigh %lu and maskLow %lu cannot be both 0.",
     179              :             maskArray[0], maskArray[1]);
     180              :     });
     181              : #endif
     182           52 :     return true;
     183              : }
     184              : 
     185              : // check mask value is in valid range
     186          144 : bool TikcppBaseCheck::CheckMaskImm(const uint64_t mask) const
     187              : {
     188              :     // counter mode: mask means element num
     189          144 :     if (ModelFactoryGetMaskMode() == 1) {
     190            0 :         if (mask > CONST_UINT32_MAX) { // only use mask[0:32] as counter mask. Only give warning!
     191            0 :             CHECK_LOG_WARNING(
     192              :                 "Failed to check mask in counter mode, mask must be in range 0 ~ %lu, current value "
     193              :                 "is %lu",
     194              :                 CONST_UINT32_MAX, mask);
     195              :         }
     196            0 :         return true;
     197              :     }
     198              :     // normal mode
     199              : #if defined(__NPU_ARCH__) && (__NPU_ARCH__ == 1001 || __NPU_ARCH__ == 2002)
     200           72 :     ASCENDC_CHECK_AND_LOG(mask != 0ULL, {
     201              :         CHECK_LOG_ERROR(
     202              :             "During calculation in normal mode in Ascend910 / Ascend310p "
     203              :             "/ Ascend610, mask %lu cannot be 0.",
     204              :             mask);
     205              :     });
     206              : #endif
     207          144 :     return true;
     208              : }
     209              : 
     210              : // when counter mode, split into norm mode with main block and tail block
     211            0 : void CounterSplitMainTail(
     212              :     std::vector<uint64_t>& maskArray, const uint32_t dtypeBytes, uint64_t& mainRepeatTimes, uint64_t& tailRepeatTimes,
     213              :     std::vector<uint64_t>& mainMaskArray, std::vector<uint64_t>& tailMaskArray)
     214              : {
     215            0 :     uint32_t oneRepeatNum = ONE_REPEAT_BYTE_SIZE / dtypeBytes;                   // when counter mode, always full mask
     216            0 :     uint64_t elementNum = (maskArray.size() == 1) ? maskArray[0] : maskArray[1]; // maskLow means element num
     217            0 :     mainRepeatTimes = elementNum / oneRepeatNum;
     218            0 :     uint64_t tailEleNum = elementNum % oneRepeatNum;
     219            0 :     tailRepeatTimes = (tailEleNum == 0) ? 0 : 1;
     220            0 :     mainMaskArray = {oneRepeatNum};
     221            0 :     tailMaskArray = {tailEleNum};
     222            0 : }
     223              : 
     224              : // calculate max extent, aka the offset of the end of all effective element
     225              : // maskLen: each repeat calculate the first maskLen elements
     226              : // blockLen: element num per block
     227              : // return: in unit of element
     228          228 : uint64_t CalculateVectorMaxOffset(
     229              :     const uint64_t repeatTimes, const uint64_t blkStride, const uint64_t repStride, const uint64_t maskLen,
     230              :     const uint64_t blockLen)
     231              : {
     232          228 :     if (repeatTimes == 0) {
     233            4 :         return 0;
     234              :     }
     235          224 :     ASSERT(blockLen != 0);
     236          224 :     uint64_t blkNumLastRep = DivCeil(maskLen, blockLen); // last repeat needs x blocks for maskLen elements
     237          224 :     uint64_t eleNumLastBlk = ((maskLen % blockLen) != 0) ? (maskLen % blockLen) : blockLen;
     238          224 :     uint64_t maxOffset = ((repeatTimes - 1) * repStride + (blkNumLastRep - 1) * blkStride) * blockLen + eleNumLastBlk;
     239          224 :     return maxOffset;
     240              : }
     241              : 
     242              : namespace {
     243              : // Given repeatTimes and stride etc, to return total buffersize needed in unit of Bytes
     244          228 : uint64_t CalculateNeededTensorSize(
     245              :     std::vector<uint64_t>& maskArray, const uint32_t dtypeBytes, const uint64_t repeatTimes, const uint64_t blkStride,
     246              :     const uint64_t repStride)
     247              : {
     248          228 :     uint64_t maskVal = (maskArray.size() == 1) ? maskArray[0] : GetMaskLength(maskArray, dtypeBytes);
     249          228 :     ASSERT(dtypeBytes != 0);
     250          228 :     uint64_t eleNumPerBlock = static_cast<uint64_t>(PlatFormParams::ONE_BLK_SIZE) / dtypeBytes;
     251          228 :     uint64_t maxOffset = CalculateVectorMaxOffset(repeatTimes, blkStride, repStride, maskVal, eleNumPerBlock);
     252          228 :     maxOffset = maxOffset * dtypeBytes;
     253          228 :     if (Int4Setter::Instance().GetInt4()) {
     254            0 :         eleNumPerBlock = static_cast<uint64_t>(PlatFormParams::ONE_BLK_SIZE) * INT4_TWO;
     255            0 :         maxOffset = CalculateVectorMaxOffset(repeatTimes, blkStride, repStride, maskVal, eleNumPerBlock);
     256            0 :         maxOffset = maxOffset / INT4_TWO;
     257            0 :         Int4Setter::Instance().ResetInt4();
     258              :     }
     259          228 :     return maxOffset;
     260              : }
     261              : 
     262              : // in counter mode, check whether the data calculated in cmd exceed the tensor size
     263              : // need to convert to norm mode with main block and tail block
     264            0 : bool CheckTensorOverflowLowCounter(
     265              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName,
     266              :     const std::string& apiName)
     267              : {
     268            0 :     std::vector<uint64_t> mainMaskArray = {0};
     269            0 :     std::vector<uint64_t> tailMaskArray = {0};
     270            0 :     uint64_t mainRepeatTimes = 0;
     271            0 :     uint64_t tailRepeatTimes = 0;
     272            0 :     CounterSplitMainTail(maskArray, params.dtypeSize, mainRepeatTimes, tailRepeatTimes, mainMaskArray, tailMaskArray);
     273              :     // when counter mode, repeatTimes given by user is not used
     274              :     // Need to compare: endpoint of mainBlock VS endpoint of tailBlock
     275              :     // Especially scenes where blkStride is much larger than repStride. mainBlock endpoint will be larger!!
     276              :     uint64_t mainBlkSize =
     277            0 :         CalculateNeededTensorSize(mainMaskArray, params.dtypeSize, mainRepeatTimes, params.blkStride, params.repStride);
     278            0 :     uint64_t maxOffset = mainBlkSize;
     279            0 :     if (tailRepeatTimes > 0) { // calculate tail block from the last repStride in main block
     280            0 :         uint64_t tailRepeatStart = mainRepeatTimes * params.repStride * ONE_BLK_SIZE;
     281            0 :         uint64_t tailBlkSize = CalculateNeededTensorSize(
     282            0 :             tailMaskArray, params.dtypeSize, tailRepeatTimes, params.blkStride, params.repStride);
     283            0 :         maxOffset = std::max(mainBlkSize, tailRepeatStart + tailBlkSize);
     284              :     }
     285            0 :     ASCENDC_CHECK(CheckTensorSizeOverflow(maxOffset, params.bufferSize, tensorName, apiName, ModeType::COUNTER_MODE));
     286            0 :     return true;
     287            0 : }
     288              : 
     289              : // in normal mode, check whether the data calculated in cmd exceed the tensor size
     290          228 : bool CheckTensorOverflowLowNorm(
     291              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName,
     292              :     const std::string& apiName)
     293              : {
     294              :     uint64_t maxOffset =
     295          228 :         CalculateNeededTensorSize(maskArray, params.dtypeSize, params.repeatTimes, params.blkStride, params.repStride);
     296          228 :     ASCENDC_CHECK(CheckTensorSizeOverflow(maxOffset, params.bufferSize, tensorName, apiName, ModeType::NORM_MODE));
     297          200 :     return true;
     298              : }
     299              : 
     300              : // in counter mode, check whether the data calculated in cmd exceed the tensor size for GatherMask
     301              : #if defined(__NPU_ARCH__) && ((__NPU_ARCH__ == 2201) || (__NPU_ARCH__ == 3002) || (__NPU_ARCH__ == 3102) || \
     302              :                               (__NPU_ARCH__ == 3510) || (__NPU_ARCH__ == 5102))
     303            0 : bool CheckTensorOverflowLowCounterGatherMask(
     304              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName)
     305              : {
     306            0 :     uint64_t maskValue = (maskArray.size() == 1) ? maskArray[0] : maskArray[1];
     307            0 :     uint64_t eleNumPerBlock = ONE_BLK_SIZE / params.dtypeSize;
     308            0 :     uint64_t blockNumPerRep = (maskValue + eleNumPerBlock - 1) / eleNumPerBlock; // total blks needed for mask num
     309            0 :     uint64_t repeatOffset = (params.repeatTimes - 1) * params.repStride * ONE_BLK_SIZE; // last repeat start pos
     310            0 :     uint64_t extraNum = blockNumPerRep * eleNumPerBlock - maskValue; // elements that do not need in tail blocks
     311            0 :     uint64_t blockOffset = ((blockNumPerRep - 1) * params.blkStride + 1) * ONE_BLK_SIZE; // endblk pos(include extraNum)
     312            0 :     uint64_t maxOffset = repeatOffset + blockOffset - extraNum * params.dtypeSize;
     313            0 :     ASCENDC_CHECK(
     314              :         CheckTensorSizeOverflow(maxOffset, params.bufferSize, tensorName, "GatherMask", ModeType::COUNTER_MODE));
     315            0 :     return true;
     316              : }
     317              : #endif
     318              : } // namespace
     319              : 
     320              : // check whether the needed size overflow the allocated buffersize, the unit is bytes.
     321          212 : bool TikcppBaseCheck::CheckTensorOverflowLow(
     322              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName) const
     323              : {
     324          212 :     if (ModelFactoryGetMaskMode() == 1) { // counter mode
     325            0 :         return CheckTensorOverflowLowCounter(maskArray, params, tensorName, apiName);
     326              :     }
     327          212 :     return CheckTensorOverflowLowNorm(maskArray, params, tensorName, apiName);
     328              : }
     329              : 
     330              : // check whether the needed size overflow the allocated buffersize, the unit is bytes.
     331            0 : bool TikcppBaseCheck::CheckTensorOverflowLowGathermask(
     332              :     std::vector<uint64_t>& maskArray, const TensorOverflowParams& params, const std::string& tensorName) const
     333              : {
     334            0 :     if (params.isCounter) { // counter mode
     335              : #if defined(__NPU_ARCH__) && ((__NPU_ARCH__ == 2201) || (__NPU_ARCH__ == 3002) || (__NPU_ARCH__ == 3102) || \
     336              :                               (__NPU_ARCH__ == 3510) || (__NPU_ARCH__ == 5102))
     337            0 :         return CheckTensorOverflowLowCounterGatherMask(maskArray, params, tensorName);
     338              : #else
     339            0 :         return CheckTensorOverflowLowCounter(maskArray, params, tensorName, apiName);
     340              : #endif
     341              :     }
     342            0 :     std::vector<uint64_t> maskArrayReal = {FULL_MASK, FULL_MASK}; // when norm mode, GatherMask neglect mask
     343            0 :     return CheckTensorOverflowLowNorm(maskArrayReal, params, tensorName, apiName);
     344            0 : }
     345              : 
     346           16 : bool TikcppBaseCheck::CheckTensorOverflowLowBrcb(
     347              :     const TensorOverflowParams& params, const std::string& tensorName) const
     348              : {
     349           32 :     std::vector<uint64_t> maskArrayReal = {FULL_MASK, FULL_MASK};
     350           32 :     return CheckTensorOverflowLowNorm(maskArrayReal, params, tensorName, apiName);
     351           16 : }
     352              : 
     353          704 : bool TikcppBaseCheck::CheckTensorAddrAlign(
     354              :     const uint64_t tensorAddr, const uint8_t phyPos, const uint64_t alignBytes, const std::string& tensorInfo) const
     355              : {
     356              :     uint64_t hardwareBaseAddr = static_cast<uint64_t>(
     357          704 :         reinterpret_cast<uintptr_t>(ConstDefiner::Instance().GetHardwareBaseAddr(static_cast<Hardware>(phyPos))));
     358          704 :     uint64_t tensorAbsPos = tensorAddr - hardwareBaseAddr;
     359          704 :     ASCENDC_CHECK_AND_LOG(((tensorAbsPos % alignBytes) == 0), {
     360              :         CHECK_LOG_ERROR(
     361              :             "Failed to check %s tensor address "
     362              :             "alignment in %s, current tensor address is %lu, which should be %lu byte aligned.",
     363              :             tensorInfo.c_str(), apiName.c_str(), tensorAbsPos, alignBytes);
     364              :     });
     365          696 :     return true;
     366              : }
     367              : 
     368              : } // namespace check
     369              : } // namespace AscendC
        

Generated by: LCOV version 2.0-1