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 : #include <pthread.h>
11 : #include <string.h>
12 : #include "securec.h"
13 : #include "vector.h"
14 : #include "error_manager.h"
15 :
16 : #define MAX_ARG_NUMBER 3
17 : #define ERRCODE_LENGTH 6
18 : #define PERCENT_S_LEN 2
19 : #define NEWLINE_LEN 2
20 : #define SPACE_NUMS 8
21 : typedef struct {
22 : char *errorId;
23 : char *errorMessage; // 模板错误message,可能带%s,跟argList是对应的
24 : char *possibleCause;
25 : char *solution;
26 : char *argList[MAX_ARG_NUMBER];
27 : } ErrorInfoConfig; // 外部错误码配置
28 :
29 : typedef struct {
30 : char *errorId;
31 : char *errorMessage; // 对于外部错误码而言,这里是格式化后的
32 : char *possibleCause;
33 : char *solution;
34 : bool idIsInner; // 标识errorId是不是常量区
35 : bool errIsInner; // 标识errorMessage是不是常量区
36 : } ErrorItem; // 兼容内外部错误信息
37 :
38 : typedef struct {
39 : size_t errorMsgLen; // 存储此次Get时返回的拼接字符串的长度
40 : size_t errorMsgSize; // 上次分配errorMsg内存大小
41 : char *errorMsg; // 存储Get时返回的拼接字符串
42 : Vector errorItemList; // 存储每次Report的错误描述;
43 : } ErrorInfoThread;
44 :
45 : // g_errorMap必须要保证按errorId保序
46 : static const ErrorInfoConfig ERROR_MAP[] = {
47 : // GE Errors
48 : {"E10001", "Value [%s] for parameter [%s] is invalid. Reason: %s", NULL /* possibleCause为空 */,
49 : "Try again with a valid argument.", {"value", "parameter", "reason"}},
50 : {"E10004", "Value for [--%s] is empty.", NULL, NULL /* solution为空 */, {"parameter"}},
51 : {"E10055", "The operation is not supported. Reason: %s", NULL, NULL, {"reason"}},
52 : {"E19001", "Failed to open file[%s]. Reason: %s.", NULL,
53 : "Fix the error according to the error message.", {"file", "errMsg"}},
54 : {"E19025", "Input tensor is invalid. Reason: %s.", NULL, NULL, {"reason"}},
55 :
56 : // RTS Errors, "EE4001"、"EE4002"、"EE4004"主线没有用到,删除
57 : {"EE1001", "The argument is invalid.Reason: %s", NULL, NULL, {"extendInfo"}},
58 : // {"EE4001", "Failed to bind the stream to the model. %s", "The stream has been bound to another model.",
59 : // "Remove the repeated binding operation on the stream from the code.", {"extend_info"}},
60 : // {"EE4002", "Failed to unbind the stream to the model. %s",
61 : // "1.The stream to be unbound is not bound to the model. 2.The model is running.",
62 : // "1.Check the code to ensure that the stream to be unbound is bound to the model."
63 : // " 2.Ensure that the model is not running.", {"extend_info"}},
64 : // {"EE4004", "Failed to enable profiling. %s", NULL, "Do not enable profiling repeatedly.", {"extend_info"}},
65 :
66 : // ACL Errors
67 : {"EH0001", "Value %s for %s is invalid. Reason: %s.", NULL, NULL, {"value", "param", "reason"}},
68 : {"EH0002", "Argument %s must not be NULL.", NULL, "Try again with a correct pointer argument.", {"param"}},
69 : {"EH0003", "Path %s is invalid. Reason: %s.", NULL, NULL, {"path", "reason"}},
70 : // {"EH0004", "File %s is invalid. Reason: %s.", NULL, NULL, {"path", "reason"}}, //主线没用到
71 : // {"EH0005", "AIPP argument %s is invalid. Reason: %s.", NULL, NULL, {"param", "reason"}}, // AIPP
72 : // {"EH0006", "%s is not supported. Reason: %s.", NULL, NULL, {"feature", "reason"}}, // DVPP跟TDT
73 :
74 : // Profiling Errors
75 : {"EK0001", "Value [%s] for [%s] is invalid. Reason: %s.", NULL, NULL, {"value", "param", "reason"}},
76 : {"EK0002", "Failed to call %s before calling %s.", NULL, NULL, {"intf1", "intf2"}},
77 : {"EK0003", "Failed to set the %s to [%s]. Reason: %s.", NULL, NULL, {"config", "value", "reason"}},
78 : {"EK0004", "[%s] is not supported in %s.", NULL, NULL, {"intf", "platform"}},
79 : {"EK0201", "Failed to allocate host memory for Profiling: %s.", "Available memory is insufficient.",
80 : "Close unused applications.", {"buf_size"}},
81 : {"EK9999", "An unknown error occurred. Please check the log.", NULL, NULL, {}},
82 : };
83 : __thread ErrorInfoThread *g_errorThread = NULL;
84 : static pthread_key_t g_errorThreadKey;
85 :
86 0 : static void KeyDestructor(void *value)
87 : {
88 0 : if ((ErrorInfoThread *)value != NULL) {
89 0 : if (((ErrorInfoThread *)value)->errorMsg != NULL) {
90 0 : free(((ErrorInfoThread *)value)->errorMsg);
91 0 : ((ErrorInfoThread *)value)->errorMsg = NULL;
92 : }
93 0 : DeInitVector(&((ErrorInfoThread *)value)->errorItemList);
94 0 : free((ErrorInfoThread *)value);
95 : }
96 0 : }
97 :
98 1 : static void PfnDestroyItem(void *a)
99 : {
100 1 : if (!((ErrorItem *)a)->idIsInner) {
101 0 : free(((ErrorItem *)a)->errorId);
102 : }
103 1 : if (!((ErrorItem *)a)->errIsInner) {
104 1 : free(((ErrorItem *)a)->errorMessage);
105 : }
106 1 : ((ErrorItem *)a)->errorId = NULL;
107 1 : ((ErrorItem *)a)->errorMessage = NULL;
108 1 : ((ErrorItem *)a)->possibleCause = NULL;
109 1 : ((ErrorItem *)a)->solution = NULL;
110 1 : }
111 :
112 1 : static void InitErrorThreadKey(void)
113 : {
114 1 : pthread_key_create(&g_errorThreadKey, KeyDestructor);
115 1 : }
116 :
117 1 : static int32_t InitErrorInfoThread(void)
118 : {
119 : static pthread_once_t once = PTHREAD_ONCE_INIT;
120 1 : pthread_once(&once, InitErrorThreadKey);
121 1 : g_errorThread = (ErrorInfoThread *)malloc(sizeof(ErrorInfoThread));
122 1 : if (g_errorThread == NULL) {
123 0 : return -1;
124 : }
125 1 : InitVector(&g_errorThread->errorItemList, sizeof(ErrorItem));
126 1 : SetVectorDestroyItem(&g_errorThread->errorItemList, PfnDestroyItem);
127 1 : g_errorThread->errorMsgLen = 0;
128 1 : g_errorThread->errorMsgSize = 0;
129 1 : g_errorThread->errorMsg = NULL;
130 1 : pthread_setspecific(g_errorThreadKey, g_errorThread);
131 1 : return 0;
132 : }
133 :
134 1 : static int Compare(const void *a, const void *b)
135 : {
136 1 : return strcmp(((const ErrorInfoConfig *)a)->errorId, ((const ErrorInfoConfig *)b)->errorId);
137 : }
138 :
139 1 : static ErrorInfoConfig *SearchFromErrorMap(const char *errorCode)
140 : {
141 1 : ErrorInfoConfig errConfig = {(char *)errorCode, NULL, NULL, NULL, {}};
142 : static size_t errorPerLen = sizeof(ERROR_MAP[0]);
143 : static size_t errorMapLen = sizeof(ERROR_MAP) / sizeof(ERROR_MAP[0]);
144 1 : return (ErrorInfoConfig *)bsearch(&errConfig, ERROR_MAP, errorMapLen, errorPerLen, Compare);
145 : }
146 :
147 1 : static int SearchFromArray(int32_t argsNum, char *args[], const char *arg)
148 : {
149 1 : int index = -1;
150 1 : for (int i = 0; i < argsNum; i++) {
151 1 : if (strcmp(args[i], arg) == 0) {
152 1 : index = i;
153 1 : break;
154 : }
155 : }
156 1 : return index;
157 : }
158 :
159 1 : static int SubString(const char *str, const char *sub)
160 : {
161 1 : int count = 0;
162 : size_t j;
163 30 : for (size_t i = 0; i < strlen(str); i++) {
164 31 : for (j = 0; j < strlen(sub); j++) {
165 30 : if (str[i + j] != sub[j]) {
166 28 : break;
167 : }
168 : }
169 29 : if (j == strlen(sub)) {
170 1 : count++;
171 : }
172 : }
173 1 : return count;
174 : }
175 :
176 : /* 函数名:FormatString
177 : 函数功能:格式化错误模板信息,如
178 : FormatString({"value", "param", "reason"}, "Value %s for %s is invalid. Reason: %s.",
179 : {"value", "param", "reason"}, {"25", "x", "The value is too small"}, 3);
180 : 返回"Value 25 for x is invalid. Reason: The value is too small.
181 : 输入:
182 : tmplArgList : 模板参数列表,如{"value", "param", "reason"}
183 : tmplErrorMsg : 模板errMsg, 如"Value %s for %s is invalid. Reason: %s."
184 : args : 用户传入的参数列表, {"value", "param", "reason", "..."}
185 : argValues : 用户传入的参数值列表, {"5", "x", "x is invalid", "..."}
186 : argsNum :用户传入的参数值或者参数列表长度, sizeof(args) / sizeof(char*)
187 : 返回值:格式化后的字符串,失败为NULL
188 : */
189 1 : static char *FormatString(char *tmplArgList[MAX_ARG_NUMBER], char *tmplErrorMsg,
190 : char *args[], char *argValues[], int32_t argsNum)
191 : { // 当模板中errormsg %s个数大于3个时,提前处理
192 1 : if (SubString(tmplErrorMsg, "%s") > MAX_ARG_NUMBER) {
193 0 : return NULL;
194 : }
195 : // 判断模板参数列表的参数是否都包含在用户传入的参数列表中,是的话计算格式化字符串长度
196 : char *validArgVals[MAX_ARG_NUMBER];
197 1 : size_t formatMsgLen = strlen(tmplErrorMsg) + 1;
198 1 : int index = -1;
199 2 : for (int i = 0; i < MAX_ARG_NUMBER; i++) {
200 2 : if (tmplArgList[i] == NULL || strlen(tmplArgList[i]) == 0) {
201 : break;
202 : }
203 1 : index = SearchFromArray(argsNum, args, tmplArgList[i]);
204 1 : if (index == -1) {
205 0 : return NULL;
206 : }
207 1 : validArgVals[i] = argValues[index];
208 1 : formatMsgLen += (strlen(argValues[index]) - PERCENT_S_LEN);
209 : }
210 1 : char *dstInfo = (char *)malloc(formatMsgLen);
211 1 : if (dstInfo == NULL) {
212 0 : return NULL;
213 : }
214 1 : int n = sprintf_s(dstInfo, formatMsgLen, tmplErrorMsg, validArgVals[0], validArgVals[1], validArgVals[2]);
215 1 : if (n < 0) {
216 0 : free(dstInfo);
217 0 : return NULL;
218 : }
219 1 : return dstInfo;
220 : }
221 :
222 1 : static int32_t Init(void)
223 : {
224 1 : if (g_errorThread == NULL) {
225 1 : int32_t initRet = InitErrorInfoThread();
226 1 : if (initRet) {
227 0 : return -1;
228 : }
229 : }
230 1 : return 0;
231 : }
232 :
233 1 : void ReportErrMessage(const char *errorCode, char *args[], char *argValues[], int32_t argsNum)
234 : {
235 1 : int32_t initRet = Init();
236 1 : if (initRet) {
237 0 : return;
238 : }
239 :
240 1 : ErrorInfoConfig *searchRet = SearchFromErrorMap(errorCode);
241 1 : if (searchRet == NULL) {
242 0 : return;
243 : }
244 :
245 : ErrorItem errorItem;
246 1 : char *ret = strstr(searchRet->errorMessage, "%s");
247 1 : if (ret == NULL) {
248 0 : errorItem.errorMessage = searchRet->errorMessage;
249 0 : errorItem.errIsInner = true;
250 : } else {
251 1 : errorItem.errorMessage = FormatString(searchRet->argList, searchRet->errorMessage, args, argValues, argsNum);
252 1 : if (errorItem.errorMessage == NULL) {
253 0 : return;
254 : }
255 1 : errorItem.errIsInner = false;
256 : }
257 1 : errorItem.idIsInner = true;
258 1 : errorItem.errorId = searchRet->errorId;
259 1 : errorItem.possibleCause = searchRet->possibleCause;
260 1 : errorItem.solution = searchRet->solution;
261 : // 为GetErrorMessage时返回拼接字符串做准备,NEWLINE_LEN表示为每条errMsg末尾增加"\r\n"
262 1 : g_errorThread->errorMsgLen += (SPACE_NUMS + strlen(errorItem.errorMessage) + NEWLINE_LEN);
263 1 : if ((EmplaceBackVector(&g_errorThread->errorItemList, &errorItem) == NULL) && (errorItem.errIsInner == false)) {
264 0 : free(errorItem.errorMessage);
265 : }
266 1 : return;
267 : }
268 :
269 3 : static bool IsValidErrorCode(const char *errorCode)
270 : {
271 3 : return strlen(errorCode) == ERRCODE_LENGTH;
272 : }
273 :
274 3 : static bool IsInnerErrorCode(const char *errorCode)
275 : {
276 3 : const char *kInterErrorCodePrefix1 = "9999";
277 3 : const char *kInterErrorCodePrefix2 = "8888";
278 3 : if (IsValidErrorCode(errorCode) && (strcmp(errorCode + PERCENT_S_LEN, kInterErrorCodePrefix1) == 0 ||
279 3 : strcmp(errorCode + PERCENT_S_LEN, kInterErrorCodePrefix2) == 0)) {
280 0 : return true;
281 : }
282 3 : return false;
283 : }
284 :
285 0 : void ReportInterErrMessage(const char *errorCode, const char *errorMsg)
286 : {
287 0 : int32_t initRet = Init();
288 0 : if (initRet) {
289 0 : return;
290 : }
291 0 : if (!IsInnerErrorCode(errorCode)) {
292 0 : return;
293 : }
294 : ErrorItem errorItem;
295 0 : size_t errCodeLen = ERRCODE_LENGTH + 1;
296 0 : errorItem.errorId = (char *)malloc(errCodeLen);
297 0 : if (errorItem.errorId == NULL) {
298 0 : return;
299 : }
300 0 : size_t errMsgLen = strlen(errorMsg) + 1;
301 0 : errorItem.errorMessage = (char *)malloc(errMsgLen);
302 0 : if (errorItem.errorMessage == NULL) {
303 0 : free(errorItem.errorId);
304 0 : return;
305 : }
306 0 : if ((memcpy_s(errorItem.errorId, errCodeLen, errorCode, errCodeLen) != EOK) ||
307 0 : (memcpy_s(errorItem.errorMessage, errMsgLen, errorMsg, errMsgLen) != EOK)) {
308 0 : free(errorItem.errorId);
309 0 : free(errorItem.errorMessage);
310 0 : return;
311 : }
312 0 : errorItem.idIsInner = false;
313 0 : errorItem.errIsInner = false;
314 : // 这里加1没加2是因为上面errMsgLen已经加了1
315 0 : g_errorThread->errorMsgLen += (SPACE_NUMS + errMsgLen + 1);
316 0 : if (EmplaceBackVector(&g_errorThread->errorItemList, &errorItem) == NULL) {
317 0 : free(errorItem.errorId);
318 0 : free(errorItem.errorMessage);
319 : }
320 0 : return;
321 : }
322 :
323 0 : void FormatReportInner(const char *errorCode, const char *fmt, ...)
324 : {
325 : va_list arg;
326 0 : va_start(arg, fmt);
327 0 : char errorStr[LIMIT_PER_MESSAGE] = {0};
328 0 : if (vsnprintf_s(errorStr, LIMIT_PER_MESSAGE, LIMIT_PER_MESSAGE - 1, fmt, arg) != -1) {
329 0 : ReportInterErrMessage(errorCode, errorStr);
330 : }
331 0 : va_end(arg);
332 0 : return;
333 : }
334 :
335 : // 根据此次计算的字符串大小和上次申请的内存大小关系,判断是否需要重新申请内存空间
336 1 : static int32_t MallocByCase(void)
337 : {
338 1 : if ((g_errorThread->errorMsgLen) > g_errorThread->errorMsgSize) {
339 1 : if (g_errorThread->errorMsg != NULL) {
340 0 : free(g_errorThread->errorMsg);
341 : }
342 1 : g_errorThread->errorMsg = (char *)malloc(g_errorThread->errorMsgLen);
343 1 : if (g_errorThread->errorMsg == NULL) {
344 0 : return -1;
345 : }
346 1 : g_errorThread->errorMsgSize = g_errorThread->errorMsgLen;
347 : }
348 1 : return 0;
349 : }
350 :
351 1 : static size_t GetFirstCode(size_t errorItemNum)
352 : {
353 1 : for (size_t i = 0; i < errorItemNum; i++) {
354 1 : if (!IsInnerErrorCode(((ErrorItem *)VectorAt(&g_errorThread->errorItemList, i))->errorId)) {
355 1 : return i;
356 : }
357 : }
358 0 : return 0;
359 : }
360 :
361 1 : static int32_t ComputeAllocate(ErrorItem *firstItem)
362 : {
363 1 : g_errorThread->errorMsgLen += (ERRCODE_LENGTH + sizeof(": Inner Error!\r\n") + strlen(firstItem->errorMessage) +
364 : NEWLINE_LEN + sizeof(" TraceBack (most recent call last): \r\n"));
365 :
366 1 : if (!IsInnerErrorCode(firstItem->errorId)) {
367 1 : if (firstItem->possibleCause != NULL) {
368 0 : g_errorThread->errorMsgLen +=
369 0 : (sizeof(" PossibleCause: ") + strlen(firstItem->possibleCause) + NEWLINE_LEN);
370 : }
371 1 : if (firstItem->solution != NULL) {
372 1 : g_errorThread->errorMsgLen += (sizeof(" Solution: ") + strlen(firstItem->solution) + NEWLINE_LEN);
373 : }
374 : }
375 1 : return MallocByCase();
376 : }
377 :
378 1 : static int32_t FormatTraceBefore(ErrorItem *firstItem)
379 : {
380 : int32_t n;
381 1 : int32_t nFirstCause = 0;
382 1 : int32_t nFirstSolution = 0;
383 1 : if (IsInnerErrorCode(firstItem->errorId)) {
384 0 : n = sprintf_s(g_errorThread->errorMsg, g_errorThread->errorMsgLen, "%s: Inner Error!\r\n%s\r\n",
385 : firstItem->errorId, firstItem->errorMessage);
386 0 : if (n < 0) {
387 0 : return -1;
388 : }
389 : } else {
390 1 : n = sprintf_s(g_errorThread->errorMsg, g_errorThread->errorMsgLen, "%s: %s\r\n",
391 : firstItem->errorId, firstItem->errorMessage);
392 1 : if (n < 0) {
393 0 : return -1;
394 : }
395 1 : if (firstItem->possibleCause != NULL) {
396 0 : nFirstCause = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen,
397 : " PossibleCause: %s\r\n", firstItem->possibleCause);
398 0 : if (nFirstCause < 0) {
399 0 : return -1;
400 : }
401 0 : n += nFirstCause;
402 : }
403 1 : if (firstItem->solution != NULL) {
404 1 : nFirstSolution = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen,
405 : " Solution: %s\r\n", firstItem->solution);
406 1 : if (nFirstSolution < 0) {
407 0 : return -1;
408 : }
409 1 : n += nFirstSolution;
410 : }
411 : }
412 1 : return n;
413 : }
414 :
415 1 : static int32_t FormatTraceAfter(ErrorItem *firstItem, size_t errorItemNum, int32_t offset)
416 : {
417 1 : bool printTracebackOnce = false;
418 1 : int32_t n = offset;
419 : int traceRet;
420 : int32_t nErrMsg;
421 : ErrorItem *errorItem;
422 2 : for (size_t i = 0; i < errorItemNum; i++) {
423 1 : errorItem = (ErrorItem *)VectorAt(&g_errorThread->errorItemList, i);
424 1 : if (strcmp(firstItem->errorId, errorItem->errorId) == 0 &&
425 1 : strcmp(firstItem->errorMessage, errorItem->errorMessage) == 0) {
426 1 : continue;
427 : }
428 0 : if (!printTracebackOnce) {
429 0 : traceRet = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen, "%s\r\n",
430 : " TraceBack (most recent call last):");
431 0 : if (traceRet < 0) {
432 0 : return -1;
433 : }
434 0 : printTracebackOnce = true;
435 0 : n += traceRet;
436 : }
437 :
438 0 : nErrMsg = sprintf_s(g_errorThread->errorMsg + n, g_errorThread->errorMsgLen, " %s\r\n",
439 : errorItem->errorMessage);
440 0 : if (nErrMsg < 0) {
441 0 : return -1;
442 : }
443 0 : n += nErrMsg;
444 : }
445 1 : return 0;
446 : }
447 :
448 1 : static bool FormatOutMsg(ErrorItem *firstItem, size_t errorItemNum)
449 : {
450 1 : int32_t offset = FormatTraceBefore(firstItem);
451 1 : if (offset == -1) {
452 0 : return false;
453 : }
454 1 : int32_t ret = FormatTraceAfter(firstItem, errorItemNum, offset);
455 1 : if (ret == -1) {
456 0 : return false;
457 : }
458 1 : return true;
459 : }
460 :
461 2 : char *GetErrorMessage(void)
462 : {
463 2 : if (g_errorThread == NULL) {
464 0 : return NULL;
465 : }
466 2 : size_t errorItemNum = VectorSize(&g_errorThread->errorItemList);
467 2 : if (errorItemNum == 0) {
468 1 : return NULL;
469 : }
470 1 : size_t index = GetFirstCode(errorItemNum);
471 1 : ErrorItem *firstItem = (ErrorItem *)VectorAt(&g_errorThread->errorItemList, index);
472 1 : int32_t allocResult = ComputeAllocate(firstItem);
473 1 : if (allocResult == -1) {
474 0 : return NULL;
475 : }
476 1 : bool ret = FormatOutMsg(firstItem, errorItemNum);
477 1 : if (!ret) {
478 0 : free(g_errorThread->errorMsg);
479 0 : g_errorThread->errorMsgLen = 0U;
480 0 : g_errorThread->errorMsgSize = 0U;
481 0 : g_errorThread->errorMsg = NULL;
482 0 : return NULL;
483 : }
484 1 : ClearVector(&g_errorThread->errorItemList);
485 1 : return g_errorThread->errorMsg;
486 : }
|