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