• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef AICPU_UTILS_KERNEL_UTIL_H_
18 #define AICPU_UTILS_KERNEL_UTIL_H_
19 
20 #include <climits>
21 #include <cmath>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 #include <map>
26 #include <memory>
27 
28 #include "inc/cpu_context.h"
29 #include "inc/kernel_log.h"
30 #include "context/common/status.h"
31 
32 namespace aicpu {
33 constexpr uint32_t kResvCpuNum = 2;
34 constexpr uint32_t kThreadNum = 32;
35 constexpr uint32_t kFirstInputIndex = 0;
36 constexpr uint32_t kSecondInputIndex = 1;
37 constexpr uint32_t kThirdInputIndex = 2;
38 constexpr uint32_t kFourthInputIndex = 3;
39 constexpr uint32_t kFirstOutputIndex = 0;
40 constexpr uint32_t kSecondOutputIndex = 1;
41 constexpr uint32_t kDynamicInput = -1;
42 constexpr uint32_t kDynamicOutput = -2;
43 constexpr uint64_t kEigenAlignmentBytes = 16;
44 
45 constexpr uint64_t kFormatNCHWIndexN = 0;
46 constexpr uint64_t kFormatNCHWIndexC = 1;
47 constexpr uint64_t kFormatNCHWIndexH = 2;
48 constexpr uint64_t kFormatNCHWIndexW = 3;
49 
50 constexpr uint64_t kFormatNC1HWC0IndexN = 0;
51 constexpr uint64_t kFormatNC1HWC0IndexC1 = 1;
52 constexpr uint64_t kFormatNC1HWC0IndexH = 2;
53 constexpr uint64_t kFormatNC1HWC0IndexW = 3;
54 constexpr uint64_t kFormatNC1HWC0IndexC0 = 4;
55 
56 constexpr uint64_t kFormatCHWIndexC = 0;
57 constexpr uint64_t kFormatCHWIndexH = 1;
58 constexpr uint64_t kFormatCHWIndexW = 2;
59 
60 constexpr uint64_t kFormatNHWCIndexN = 0;
61 constexpr uint64_t kFormatNHWCIndexH = 1;
62 constexpr uint64_t kFormatNHWCIndexW = 2;
63 constexpr uint64_t kFormatNHWCIndexC = 3;
64 
65 constexpr uint64_t kFormatHWCIndexH = 0;
66 constexpr uint64_t kFormatHWCIndexW = 1;
67 constexpr uint64_t kFormatHWCIndexC = 2;
68 
69 const size_t INPUT_NUM0 = 0;
70 const size_t INPUT_NUM1 = 1;
71 const size_t INPUT_NUM2 = 2;
72 const size_t INPUT_NUM3 = 3;
73 const size_t INPUT_NUM4 = 4;
74 const size_t INPUT_NUM5 = 5;
75 const size_t INPUT_NUM6 = 6;
76 const size_t INPUT_NUM7 = 7;
77 const size_t INPUT_NUM8 = 8;
78 const size_t INPUT_NUM9 = 9;
79 const size_t INPUT_NUM32 = 32;
80 
81 using TensorShapePtr = std::shared_ptr<TensorShape>;
82 
83 /*
84  * str cat util function
85  * param[in] params need concat to string
86  * return concatted string
87  */
88 template <typename T>
ConcatString(T arg)89 std::string ConcatString(T arg) {
90   std::ostringstream oss;
91   oss << arg;
92   return oss.str();
93 }
94 
95 template <typename T, typename... Ts>
ConcatString(T arg,Ts...arg_left)96 std::string ConcatString(T arg, Ts... arg_left) {
97   std::ostringstream oss;
98   oss << arg;
99   oss << ConcatString(arg_left...);
100   return oss.str();
101 }
102 
103 /**
104  * @brief get debug string of vector
105  * @param values values in vector
106  * @return string of values
107  */
108 template <typename T>
VectorToString(const std::vector<T> & values)109 inline std::string VectorToString(const std::vector<T> &values) {
110   std::stringstream ss;
111   for (auto iter = values.begin(); iter != values.end(); ++iter) {
112     ss << *iter;
113     if (iter != values.end() - 1) {
114       ss << ", ";
115     }
116   }
117   return ss.str();
118 }
119 
120 template <typename T>
FmtToStr(const T & t)121 std::string FmtToStr(const T &t) {
122   std::string fmt;
123   std::stringstream st;
124   st << "[" << t << "]";
125   fmt = st.str();
126   return fmt;
127 }
128 
129 std::string FormatToSerialString(CpuKernelContext &ctx, Format format);
130 
131 /**
132  * Get primary-format from format,
133  * in bits field:
134  * ------------------------------------------
135  * |  1 byte  |   2 bytes  |     1 byt      |
136  * |----------|------------|----------------|
137  * | reserved | sub-format | primary-format |
138  * ------------------------------------------
139  * @param format
140  * @return
141  */
GetPrimaryFormat(int32_t format)142 inline int32_t GetPrimaryFormat(int32_t format) { return static_cast<int32_t>(static_cast<uint32_t>(format) & 0xff); }
143 
GetSubFormat(int32_t format)144 inline int32_t GetSubFormat(int32_t format) {
145   return static_cast<int32_t>((static_cast<uint32_t>(format) & 0xffff00) >> 8);
146 }
147 
HasSubFormat(int32_t format)148 inline bool HasSubFormat(int32_t format) { return GetSubFormat(format) > 0; }
149 
150 /**
151  * @brief Judge whether tensor is empty
152  * @param tensor need judged tensor
153  * @return true: is empty tensor, false: isn't empty tensor
154  */
155 bool IsEmptyTensor(Tensor *tensor);
156 
157 /**
158  * @brief multiply two nonnegative int64's
159  * @param x mul value x
160  * @param y mul value y
161  * @param xy product of x and y
162  * @return true: normal, false: overflow
163  */
MulWithoutOverflow(CpuKernelContext & ctx,const int64_t x,const int64_t y,int64_t & xy)164 inline bool MulWithoutOverflow(CpuKernelContext &ctx, const int64_t x, const int64_t y, int64_t &xy) {
165   // Multiply in uint64 rather than int64 since signed overflow is undefined.
166   // Negative values will wrap around to large unsigned values in the casts
167   // (see section 4.7 [conv.integral] of the C++14 standard).
168   const uint64_t ux = static_cast<uint64_t>(x);
169   const uint64_t uy = static_cast<uint64_t>(y);
170   const uint64_t uxy = ux * uy;
171 
172   // Check if we overflow uint64, using a cheap check if both inputs are small
173   if ((ux | uy) >> 32 != 0) {
174     // Ensure nonnegativity.  Note that negative numbers will appear "large"
175     // to the unsigned comparisons above.
176     if (x < 0 || y < 0) {
177       CUST_KERNEL_LOG_ERROR(ctx, "Can't multiply negative numbers.");
178       return false;
179     }
180 
181     // Otherwise, detect overflow using a division
182     if (ux != 0 && uxy / ux != uy) {
183       return false;
184     }
185   }
186 
187   // Cast back to signed.  Any negative value will signal an error.
188   xy = static_cast<int64_t>(uxy);
189   return true;
190 }
191 
192 /**
193  * @brief add two int64's
194  * @param x add value x
195  * @param y add value y
196  * @param sum sum of x and y
197  * @return true: normal, false: overflow
198  */
AddWithoutOverflow(const int64_t x,const int64_t y,int64_t & sum)199 inline bool AddWithoutOverflow(const int64_t x, const int64_t y, int64_t &sum) {
200   const uint64_t ux = static_cast<uint64_t>(x);
201   const uint64_t uy = static_cast<uint64_t>(y);
202   const uint64_t usum = ux + uy;
203   sum = static_cast<int64_t>(usum);
204 
205   return !(((x >= 0) == (y >= 0)) && ((sum >= 0) != (x >= 0)));
206 }
207 
208 /**
209  * @brief check two shape vector are same
210  * @param shape shape
211  * @param check_shape check_shape
212  * @return true: same, false: different
213  */
ShapeVectorIsSame(const std::vector<int64_t> & shape,const std::vector<int64_t> & check_shape)214 inline bool ShapeVectorIsSame(const std::vector<int64_t> &shape, const std::vector<int64_t> &check_shape) {
215   if (shape.size() != check_shape.size()) {
216     return false;
217   } else {
218     for (size_t index = 0; index < shape.size(); ++index) {
219       if (shape[index] != check_shape[index]) {
220         return false;
221       }
222     }
223   }
224   return true;
225 }
226 
227 /**
228  * @brief normal check for calculation
229  * @param ctx context
230  * @return status code
231  */
232 uint32_t NormalMathCheck(CpuKernelContext &ctx);
233 
234 /**
235  * @brief normal check for kernel
236  * @param ctx context
237  * @param inputs_num num of inputs
238  * @param outputs_num num of outputs
239  * @return status code
240  */
241 uint32_t NormalCheck(CpuKernelContext &ctx, const uint32_t inputs_num, const uint32_t outputs_num);
242 
243 /**
244  * @brief normal check for kernel
245  * @param ctx context
246  * @param inputs_num num of inputs
247  * @param outputs_num num of outputs
248  * @param attr_names names of attrs
249  * @return status code
250  */
251 uint32_t NormalCheck(CpuKernelContext &ctx, const uint32_t inputs_num, const uint32_t outputs_num,
252                      const std::vector<std::string> &attr_names);
253 
254 bool IsScalar(const std::vector<int64_t> &shape);
255 
256 bool IsMatrix(const std::vector<int64_t> &shape);
257 
258 bool IsVector(const std::vector<int64_t> &shape);
259 
260 bool IsSquareMatrix(const std::vector<int64_t> &shape);
261 /**
262  * @brief check if addr is aligned
263  * @param addr address for check
264  * @return true: aligned, false: not aligned
265  */
266 bool AddrAlignedCheck(const void *addr, uint64_t alignment = kEigenAlignmentBytes);
267 
268 bool IsVectorOrHigher(const std::vector<int64_t> &shape);
269 
270 /**
271  * @brief get data type from string
272  * @param dtype_str string of data type
273  * @return DataType
274  */
275 DataType DType(std::string dtype_str);
276 
277 /**
278  * @brief get string from data type
279  * @param dtype data type
280  * @return string of data type
281  */
282 std::string DTypeStr(DataType dtype);
283 
284 /**
285  * @brief check tensor type is same
286  * @param types a map with name and data type
287  * @param check_type check_type
288  * @param prim_name ops name
289  * @return status code
290  */
291 uint32_t CheckTensorTypeSame(CpuKernelContext &ctx, const std::map<std::string, DataType> &types,
292                              const DataType &check_type, const std::string &prim_name);
293 
294 /**
295  * @brief check tensor type is same
296  * @param shapes a map with name and shape
297  * @param check_type check_shape
298  * @param prim_name ops name
299  * @return status code
300  */
301 uint32_t CheckTensorShapeSame(CpuKernelContext &ctx, const std::map<std::string, TensorShapePtr> &shapes,
302                               const std::vector<int64_t> &check_shape, const std::string &prim_name);
303 
IntToSize(CpuKernelContext & ctx,int u)304 inline size_t IntToSize(CpuKernelContext &ctx, int u) {
305   if (u < 0) {
306     CUST_AICPU_LOGE(ctx, "The int value [%d] is less than 0.", u);
307     return SIZE_MAX;
308   }
309   return static_cast<size_t>(u);
310 }
311 
SizeToInt(CpuKernelContext & ctx,size_t u)312 inline int SizeToInt(CpuKernelContext &ctx, size_t u) {
313   if (u > static_cast<size_t>((std::numeric_limits<int>::max)())) {
314     CUST_AICPU_LOGE(ctx, "The size_t value [%lu] exceeds the maximum value of int.", u);
315     return INT_MAX;
316   }
317   return static_cast<int>(u);
318 }
319 
LongToSize(CpuKernelContext & ctx,int64_t u)320 inline size_t LongToSize(CpuKernelContext &ctx, int64_t u) {
321   if (u < 0) {
322     CUST_AICPU_LOGE(ctx, "The int64_t value [%ld] is less than 0.", u);
323     return SIZE_MAX;
324   }
325   return static_cast<size_t>(u);
326 }
327 
LongToInt(CpuKernelContext & ctx,int64_t u)328 inline int32_t LongToInt(CpuKernelContext &ctx, int64_t u) {
329   if (u > static_cast<int64_t>((std::numeric_limits<int32_t>::max)())) {
330     CUST_AICPU_LOGE(ctx, "The size_t value [%ld] exceeds the maximum value of int.", u);
331     return INT_MAX;
332   }
333   return static_cast<int32_t>(u);
334 }
335 }  // namespace aicpu
336 #endif
337