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
|