已合并
feat: 新增acldumpSaveExceptionInfo/acldumpGetExceptionInfoPath接口 #3993
yring_8创建于 8月1日
feat: 新增acldumpSaveExceptionInfo/acldumpGetExceptionInfoPath接口 #3993
已合并
yring_8创建于 8月1日
已删除 :save_exception合入到cann/runtimemaster
36 个文件变更+1650-81
@@ -4,12 +4,14 @@
4 4 
5- [`aclError aclmdlInitDump()`](#aclmdlInitDump):Dump初始化。5- [`aclError aclmdlInitDump()`](#aclmdlInitDump):Dump初始化。
6- [`aclError aclmdlSetDump(const char *dumpCfgPath)`](#aclmdlSetDump):设置Dump参数。6- [`aclError aclmdlSetDump(const char *dumpCfgPath)`](#aclmdlSetDump):设置Dump参数。
7-- [`aclError acldumpRegCallback(int32_t (* const messageCallback)(const acldumpChunk *, int32_t len), int32_t flag)`](#acldumpRegCallback):Dump数据回调函数注册接口。7+- [`aclError acldumpRegCallback(int32_t (* const messageCallback)(const acldumpChunk *, int32_t), int32_t flag)`](#acldumpRegCallback):Dump数据回调函数注册接口。
8- [`void acldumpUnregCallback()`](#acldumpUnregCallback):Dump数据回调函数取消注册接口。8- [`void acldumpUnregCallback()`](#acldumpUnregCallback):Dump数据回调函数取消注册接口。
9-- [`const char* acldumpGetPath(acldumpType dumpType)`](#acldumpGetPath):获取Dump数据存路径,以便用户将自定维测数据保存到该路径下。9+- [`const char* acldumpGetPath(acldumpType dumpType)`](#acldumpGetPath):获取Dump数据路径,以便用户将自定维测数据保存到该路径下。
10- [`aclError aclmdlFinalizeDump()`](#aclmdlFinalizeDump):Dump去初始化。10- [`aclError aclmdlFinalizeDump()`](#aclmdlFinalizeDump):Dump去初始化。
11- [`aclError aclopStartDumpArgs(uint32_t dumpType, const char *path)`](#aclopStartDumpArgs):调用本接口开启算子信息统计功能,并需与[aclopStopDumpArgs](#aclopStopDumpArgs)接口配合使用,将算子信息文件输出到path参数指定的目录,一个shape对应一个算子信息文件,文件中包含算子类型、算子属性、算子输入&输出的format/数据类型/shape等信息。11- [`aclError aclopStartDumpArgs(uint32_t dumpType, const char *path)`](#aclopStartDumpArgs):调用本接口开启算子信息统计功能,并需与[aclopStopDumpArgs](#aclopStopDumpArgs)接口配合使用,将算子信息文件输出到path参数指定的目录,一个shape对应一个算子信息文件,文件中包含算子类型、算子属性、算子输入&输出的format/数据类型/shape等信息。
12- [`aclError aclopStopDumpArgs(uint32_t dumpType)`](#aclopStopDumpArgs):调用本接口关闭算子信息统计功能,并需与[aclopStartDumpArgs](#aclopStartDumpArgs)接口配合使用,将算子信息文件输出到path参数指定的目录,一个shape对应一个算子信息文件,文件中包含算子类型、算子属性、算子输入&输出的format/数据类型/shape等信息。12- [`aclError aclopStopDumpArgs(uint32_t dumpType)`](#aclopStopDumpArgs):调用本接口关闭算子信息统计功能,并需与[aclopStartDumpArgs](#aclopStartDumpArgs)接口配合使用,将算子信息文件输出到path参数指定的目录,一个shape对应一个算子信息文件,文件中包含算子类型、算子属性、算子输入&输出的format/数据类型/shape等信息。
13+- [`aclError acldumpGetExceptionInfoPath(char *path, size_t maxLen)`](#acldumpGetExceptionInfoPath):获取异常算子Dump数据的存储路径,以便用户将自定义维测数据保存到该路径下,导出的数据用于分析AI Core Error问题。
14+- [`aclError acldumpSaveExceptionInfo(const char *fileName, const char *userTag, const acldumpTensorInfo *tensors, size_t tensorCount)`](#acldumpSaveExceptionInfo):调用本接口将自定义异常算子Tensor数据保存到异常算子Dump数据的存储路径下,导出的数据用于分析AI Core Error问题。
13 15 
14<a id="aclmdlInitDump"></a>16<a id="aclmdlInitDump"></a>
15 17 
@@ -201,9 +203,11 @@ aclError aclmdlSetDump(const char *dumpCfgPath)
201}203}
202```204```
203 205 
206+<a id="exception_dump_config"></a>
207+ 
204### 配置文件示例(异常算子Dump配置)208### 配置文件示例(异常算子Dump配置)
205 209 
206-**异常算子Dump配置**(用于导出异常算子的输入输出数据、workspace信息、Tiling信息),导出的数据用于分析AI Core Error问题。默认不启用该Dump配置210+**异常算子Dump配置**(用于导出异常算子的输入输出数据、workspace信息、Tiling信息),导出的数据用于分析AI Core Error问题。默认不启用该Dump配置
207 211 
208通过配置dump\_scene参数值开启异常算子Dump功能,配置文件中的示例内容如下,表示开启轻量化的exception dump:212通过配置dump\_scene参数值开启异常算子Dump功能,配置文件中的示例内容如下,表示开启轻量化的exception dump:
209 213 
@@ -396,7 +400,7 @@ aclError aclmdlSetDump(const char *dumpCfgPath)
396## acldumpRegCallback400## acldumpRegCallback
397 401 
398```c402```c
399-aclError acldumpRegCallback(int32_t (* const messageCallback)(const acldumpChunk *, int32_t len), int32_t flag)403+aclError acldumpRegCallback(int32_t (* const messageCallback)(const acldumpChunk *, int32_t), int32_t flag)
400```404```
401 405 
402### 产品支持情况406### 产品支持情况
@@ -573,7 +577,7 @@ const char* acldumpGetPath(acldumpType dumpType)
573 577 
574### 功能说明578### 功能说明
575 579 
576-获取Dump数据存路径,以便用户将自定义维测数据保存到该路径下。580+获取Dump数据路径,以便用户将自定义维测数据保存到该路径下。
577 581 
578在调用本接口前,需通过[aclmdlInitDump](#aclmdlInitDump)接口初始化Dump功能、通过[aclmdlSetDump](#aclmdlSetDump)接口配置Dump信息,或者直接通过[aclInit](02_initialization_and_deinitialization.md#aclInit)接口配置Dump信息。582在调用本接口前,需通过[aclmdlInitDump](#aclmdlInitDump)接口初始化Dump功能、通过[aclmdlSetDump](#aclmdlSetDump)接口配置Dump信息,或者直接通过[aclInit](02_initialization_and_deinitialization.md#aclInit)接口配置Dump信息。
579 583 
@@ -779,3 +783,127 @@ aclError aclopStopDumpArgs(uint32_t dumpType)
779 783 
780仅支持在单算子API执行(例如,接口名前缀为aclnn的接口)场景下使用本接口,否则无法生成dump文件。784仅支持在单算子API执行(例如,接口名前缀为aclnn的接口)场景下使用本接口,否则无法生成dump文件。
781<!-- end id11 -->785<!-- end id11 -->
786+ 
787+<br>
788+<br>
789+<br>
790+ 
791+<a id="acldumpGetExceptionInfoPath"></a>
792+ 
793+## acldumpGetExceptionInfoPath
794+ 
795+```c
796+aclError acldumpGetExceptionInfoPath(char *path, size_t maxLen)
797+```
798+ 
799+### 产品支持情况
800+ 
801+<!-- npu="950" id9001 -->
802+- Ascend 950PR/Ascend 950DT:支持
803+<!-- end id9001 -->
804+<!-- npu="A3" id9002 -->
805+- Atlas A3 训练系列产品/Atlas A3 推理系列产品:支持
806+<!-- end id9002 -->
807+<!-- npu="910b" id9003 -->
808+- Atlas A2 训练系列产品/Atlas A2 推理系列产品:支持
809+<!-- end id9003 -->
810+<!-- npu="310b" id9004 -->
811+- Atlas 200I/500 A2 推理产品:支持
812+<!-- end id9004 -->
813+<!-- npu="310p" id9005 -->
814+- Atlas 推理系列产品:支持
815+<!-- end id9005 -->
816+<!-- npu="910" id9006 -->
817+- Atlas 训练系列产品:支持
818+<!-- end id9006 -->
819+<!-- npu="IPV350" id9007 -->
820+- IPV350:不支持
821+<!-- end id9007 -->
822+<!-- @ref: runtime/res/docs/zh/api_ref/18_dump_configuration_res.md#id9 -->
823+ 
824+### 功能说明
825+ 
826+获取异常算子Dump数据的存储路径,以便用户将自定义维测数据保存到该路径下,导出的数据用于分析AI Core Error问题。输出路径格式为:`<dumpPath>/extra-info/data-dump/<deviceId>/`。其中:
827+ 
828+ - dumpPath:开启异常算子Dump时配置的存储路径。
829+ - deviceId:当前正在使用的Device的ID。
830+ 
831+### 参数说明
832+ 
833+| 参数名 | 输入/输出 | 说明 |
834+| --- | :---: | --- |
835+| path | 输出 | 用于接收路径的字符数组。该数组内存空间由调用方提前申请,且能够满足可接收路径的内存大小(建议为4096字节)。 |
836+| maxLen | 输入 | path参数的内存大小。 |
837+ 
838+### 返回值说明
839+ 
840+返回0(ACL_SUCCESS)表示成功,返回其他值表示失败,请参见[aclError](25-01_aclError.md#aclError)。
841+ 
842+### 约束说明
843+ 
844+- 本接口需在开启异常算子Dump功能后调用,详细配置请参见[aclInit(异常算子Dump配置)](02_initialization_and_deinitialization.md#aclInit)或[aclmdlSetDump(异常算子Dump配置)](#exception_dump_config)或环境变量[ASCEND\_DUMP\_SCENE](https://hiascend.com/document/redirect/CannCommunityEnvRef)。
845+ 
846+<br>
847+<br>
848+<br>
849+ 
850+<a id="acldumpSaveExceptionInfo"></a>
851+ 
852+## acldumpSaveExceptionInfo
853+ 
854+```c
855+aclError acldumpSaveExceptionInfo(const char *fileName, const char *userTag, const acldumpTensorInfo *tensors, size_t tensorCount)
856+```
857+ 
858+### 产品支持情况
859+ 
860+<!-- npu="950" id9008 -->
861+- Ascend 950PR/Ascend 950DT:支持
862+<!-- end id9008 -->
863+<!-- npu="A3" id9009 -->
864+- Atlas A3 训练系列产品/Atlas A3 推理系列产品:支持
865+<!-- end id9009 -->
866+<!-- npu="910b" id9010 -->
867+- Atlas A2 训练系列产品/Atlas A2 推理系列产品:支持
868+<!-- end id9010 -->
869+<!-- npu="310b" id9011 -->
870+- Atlas 200I/500 A2 推理产品:支持
871+<!-- end id9011 -->
872+<!-- npu="310p" id9012 -->
873+- Atlas 推理系列产品:支持
874+<!-- end id9012 -->
875+<!-- npu="910" id9013 -->
876+- Atlas 训练系列产品:支持
877+<!-- end id9013 -->
878+<!-- npu="IPV350" id9014 -->
879+- IPV350:不支持
880+<!-- end id9014 -->
881+<!-- @ref: runtime/res/docs/zh/api_ref/18_dump_configuration_res.md#id10 -->
882+ 
883+### 功能说明
884+ 
885+调用本接口将自定义异常算子Tensor数据保存到异常算子Dump数据的存储路径下,导出的数据用于分析AI Core Error问题。
886+ 
887+数据文件的实际存储路径格式为:`<dumpPath>/extra-info/data-dump/<deviceId>/<fileName>.custom.{timestamp}`。其中:
888+ 
889+ - dumpPath:开启异常算子Dump时配置的存储路径。
890+ - deviceId:当前正在使用的Device的ID。
891+ - fileName:fileName参数。
892+ - timestamp:毫秒级时间戳。
893+ 
894+### 参数说明
895+ 
896+| 参数名 | 输入/输出 | 说明 |
897+| --- | :---: | --- |
898+| fileName | 输入 | 目标文件名。支持为异常算子Dump数据存储路径的相对路径,且不能包含“..”路径段。 |
899+| userTag | 输入 | 待保存的自定义维测信息,可选参数。 |
900+| tensors | 输入 | 待保存的tensors数组,数组有效长度不得小于tensorCount。Tensor类型定义请参见[acldumpTensorInfo](25-04_Structs.md#acldumpTensorInfo)。其中,acldumpTensorInfo.addrType只支持ACL_DUMP_ADDR_RAW,acldumpTensorInfo.placement只支持ACL_DUMP_PLACEMENT_DEVICE。 |
901+| tensorCount | 输入 | tensors数组中的元素个数,需由调用方保证与数组实际长度一致。 |
902+ 
903+### 返回值说明
904+ 
905+返回0(ACL_SUCCESS)表示成功,返回其他值表示失败,请参见[aclError](25-01_aclError.md#aclError)。
906+ 
907+### 约束说明
908+ 
909+- 本接口需在开启异常算子Dump功能后调用,详细配置请参见[aclInit(异常算子Dump配置)](02_initialization_and_deinitialization.md#aclInit)或[aclmdlSetDump(异常算子Dump配置)](#exception_dump_config)或环境变量[ASCEND\_DUMP\_SCENE](https://hiascend.com/document/redirect/CannCommunityEnvRef)。
@@ -8,6 +8,9 @@ enum 类型数据。
8- [aclCANNPackageName](#aclCANNPackageName)8- [aclCANNPackageName](#aclCANNPackageName)
9- [aclDataType](#aclDataType)9- [aclDataType](#aclDataType)
10- [aclDeviceInfo](#aclDeviceInfo)10- [aclDeviceInfo](#aclDeviceInfo)
11+- [acldumpTensorAddressType](#acldumpTensorAddressType)
12+- [acldumpTensorPlacement](#acldumpTensorPlacement)
13+- [acldumpTensorType](#acldumpTensorType)
11- [acldumpType](#acldumpType)14- [acldumpType](#acldumpType)
12- [aclFormat](#aclFormat)15- [aclFormat](#aclFormat)
13- [aclmdlRICaptureMode](#aclmdlRICaptureMode)16- [aclmdlRICaptureMode](#aclmdlRICaptureMode)
@@ -190,18 +193,78 @@ typedef enum {
190 193 
191<br>194<br>
192 195 
196+<a id="acldumpTensorAddressType"></a>
197+ 
198+## acldumpTensorAddressType
199+ 
200+```c
201+typedef enum acldumpTensorAddressType {
202+ ACL_DUMP_ADDR_PTR = 0,
203+ ACL_DUMP_ADDR_PTR_PTR,
204+ ACL_DUMP_ADDR_RAW
205+} acldumpTensorAddressType;
206+```
207+ 
208+| 枚举项 | 说明 |
209+| --- | --- |
210+| ACL_DUMP_ADDR_PTR | address是二级地址,数据地址需要一次解引用。 |
211+| ACL_DUMP_ADDR_PTR_PTR | address是三级地址,数据地址需要二次解引用。 |
212+| ACL_DUMP_ADDR_RAW | address是裸地址,直接是数据地址。 |
213+ 
214+<br>
215+ 
216+<a id="acldumpTensorPlacement"></a>
217+ 
218+## acldumpTensorPlacement
219+ 
220+```c
221+typedef enum acldumpTensorPlacement {
222+ ACL_DUMP_PLACEMENT_DEVICE = 0,
223+ ACL_DUMP_PLACEMENT_HOST,
224+ ACL_DUMP_PLACEMENT_END
225+} acldumpTensorPlacement;
226+```
227+ 
228+| 枚举项 | 说明 |
229+| --- | --- |
230+| ACL_DUMP_PLACEMENT_DEVICE | tensor位于Device。 |
231+| ACL_DUMP_PLACEMENT_HOST | tensor位于Host。 |
232+| ACL_DUMP_PLACEMENT_END | 枚举值的边界,为预留值,不是有效的tensor位置。 |
233+ 
234+<br>
235+ 
236+<a id="acldumpTensorType"></a>
237+ 
238+## acldumpTensorType
239+ 
240+```c
241+typedef enum acldumpTensorType {
242+ ACL_DUMP_TENSOR_INPUT = 0,
243+ ACL_DUMP_TENSOR_OUTPUT,
244+ ACL_DUMP_TENSOR_WORKSPACE
245+} acldumpTensorType;
246+```
247+ 
248+| 枚举项 | 说明 |
249+| --- | --- |
250+| ACL_DUMP_TENSOR_INPUT | 输入tensor。 |
251+| ACL_DUMP_TENSOR_OUTPUT | 输出tensor。 |
252+| ACL_DUMP_TENSOR_WORKSPACE | Workspace tensor。 |
253+ 
254+<br>
255+ 
193<a id="acldumpType"></a>256<a id="acldumpType"></a>
194 257 
195## acldumpType258## acldumpType
196 259 
197```c260```c
198-enum acldumpType {261+typedef enum acldumpType {
199 AIC_ERR_BRIEF_DUMP = 1, // 轻量化exception dump262 AIC_ERR_BRIEF_DUMP = 1, // 轻量化exception dump
200 AIC_ERR_NORM_DUMP = 2, // 普通exception dump,在轻量化exception dump基础上,还会导出Shape、Data Type、Format以及属性信息263 AIC_ERR_NORM_DUMP = 2, // 普通exception dump,在轻量化exception dump基础上,还会导出Shape、Data Type、Format以及属性信息
201 AIC_ERR_DETAIL_DUMP = 3, // 在轻量化exception dump基础上,还会导出AI Core的内部存储、寄存器以及调用栈信息264 AIC_ERR_DETAIL_DUMP = 3, // 在轻量化exception dump基础上,还会导出AI Core的内部存储、寄存器以及调用栈信息
202 DATA_DUMP = 4, // 模型Dump配置、单算子Dump配置265 DATA_DUMP = 4, // 模型Dump配置、单算子Dump配置
203 OVERFLOW_DUMP = 5 // 溢出算子Dump266 OVERFLOW_DUMP = 5 // 溢出算子Dump
204-};267+} acldumpType;
205```268```
206 269 
207<br>270<br>
@@ -5,6 +5,7 @@ struct 类型数据。
5<br>5<br>
6 6 
7- [aclCANNPackageVersion](#aclCANNPackageVersion)7- [aclCANNPackageVersion](#aclCANNPackageVersion)
8+- [acldumpTensorInfo](#acldumpTensorInfo)
8- [aclmdlRICondTaskParams](#aclmdlRICondTaskParams)9- [aclmdlRICondTaskParams](#aclmdlRICondTaskParams)
9- [aclmdlRIEventRecordTaskParams](#aclmdlRIEventRecordTaskParams)10- [aclmdlRIEventRecordTaskParams](#aclmdlRIEventRecordTaskParams)
10- [aclmdlRIEventResetTaskParams](#aclmdlRIEventResetTaskParams)11- [aclmdlRIEventResetTaskParams](#aclmdlRIEventResetTaskParams)
@@ -75,6 +76,46 @@ typedef struct aclCANNPackageVersion {
75 76 
76<br>77<br>
77 78 
79+<a id="acldumpTensorInfo"></a>
80+ 
81+## acldumpTensorInfo
82+ 
83+```c
84+#define ACL_DUMP_MAX_SHAPE_NUM 25
85+ 
86+typedef struct acldumpTensorInfo {
87+ acldumpTensorType type;
88+ size_t tensorSize;
89+ int32_t format;
90+ int32_t dataType;
91+ int64_t *tensorAddr;
92+ acldumpTensorAddressType addrType;
93+ acldumpTensorPlacement placement;
94+ uint32_t argsOffset;
95+ uint32_t shapeNum;
96+ uint32_t originShapeNum;
97+ uint64_t shape[ACL_DUMP_MAX_SHAPE_NUM];
98+ uint64_t originShape[ACL_DUMP_MAX_SHAPE_NUM];
99+} acldumpTensorInfo;
100+```
101+ 
102+| 成员名称 | 说明 |
103+| --- | --- |
104+| type | tensor类型。类型定义请参见[acldumpTensorType](25-02_Enumerations.md#acldumpTensorType)。 |
105+| tensorSize | tensor大小,单位Byte。 |
106+| format | tensor数据格式。类型定义值请参见[aclFormat](25-02_Enumerations.md#aclFormat)。 |
107+| dataType | tensor数据类型。类型定义值请参见[aclDataType](25-02_Enumerations.md#aclDataType)。 |
108+| tensorAddr | tensor地址。 |
109+| addrType | tensor地址类型。类型定义请参见[acldumpTensorAddressType](25-02_Enumerations.md#acldumpTensorAddressType)。 |
110+| placement | tensor数据位置。类型定义请参见[acldumpTensorPlacement](25-02_Enumerations.md#acldumpTensorPlacement)。 |
111+| argsOffset | tensor基于算子首参数的偏移位置。 |
112+| shapeNum | tensor shape有效维度大小,不超过ACL_DUMP_MAX_SHAPE_NUM。 |
113+| originShapeNum | tensor原始shape有效维度大小,不超过ACL_DUMP_MAX_SHAPE_NUM。 |
114+| shape | tensor shape维度数组。 |
115+| originShape | tensor原始shape维度数组。 |
116+ 
117+<br>
118+ 
78<a id="aclmdlRICondTaskParams"></a>119<a id="aclmdlRICondTaskParams"></a>
79 120 
80## aclmdlRICondTaskParams121## aclmdlRICondTaskParams
@@ -9,6 +9,7 @@
9 9 
10| 产品 | 是否支持 |10| 产品 | 是否支持 |
11| --- | --- |11| --- | --- |
12+| Ascend 950PR/Ascend 950DT | √ |
12| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |13| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
13| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |14| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
14 15 
@@ -9,6 +9,7 @@ This sample supports the following products:
9 9 
10| Product | Supported |10| Product | Supported |
11| --- | --- |11| --- | --- |
12+| Ascend 950PR/Ascend 950DT | Yes |
12| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |13| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |
13| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |14| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |
14 15 
@@ -9,6 +9,7 @@
9 9 
10| 产品 | 是否支持 |10| 产品 | 是否支持 |
11| --- | --- |11| --- | --- |
12+| Ascend 950PR/Ascend 950DT | √ |
12| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |13| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
13| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |14| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
14 15 
@@ -9,6 +9,7 @@ This sample supports the following products:
9 9 
10| Product | Supported |10| Product | Supported |
11| --- | --- |11| --- | --- |
12+| Ascend 950PR/Ascend 950DT | Yes |
12| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |13| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |
13| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |14| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |
14 15 
@@ -9,6 +9,7 @@
9 9 
10| 产品 | 是否支持 |10| 产品 | 是否支持 |
11| --- | --- |11| --- | --- |
12+| Ascend 950PR/Ascend 950DT | √ |
12| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |13| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
13| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |14| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
14 15 
@@ -9,6 +9,7 @@ This sample supports the following products:
9 9 
10| Product | Supported |10| Product | Supported |
11| --- | --- |11| --- | --- |
12+| Ascend 950PR/Ascend 950DT | Yes |
12| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |13| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |
13| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |14| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |
14 15 
@@ -0,0 +1,37 @@
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+# CMake lowest version requirement
12+cmake_minimum_required(VERSION 3.16.0)
13+ 
14+# Project information
15+project(Adump_Save_Exception_Info_Sample)
16+set(SOC_VERSION $ENV{SOC_VERSION})
17+set(ASCENDC_CMAKE_DIR $ENV{ASCENDC_CMAKE_DIR})
18+set(RUN_MODE "npu" CACHE STRING "run mode: npu")
19+set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Build type Release/Debug (default Debug)" FORCE)
20+set(CMAKE_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_DIR}/out" CACHE STRING "path for install()" FORCE)
21+ 
22+include(${ASCENDC_CMAKE_DIR}/ascendc.cmake)
23+ 
24+include_directories(${ASCEND_CANN_PACKAGE_PATH}/include
25+ ${ASCEND_CANN_PACKAGE_PATH}/aclnn
26+ ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
27+ 
28+link_directories(${ASCEND_CANN_PACKAGE_PATH}/lib64)
29+ 
30+add_executable(main main.cpp)
31+ 
32+target_link_libraries(main PRIVATE
33+ ${ASCEND_CANN_PACKAGE_PATH}/lib64/libascendcl.so
34+ ${ASCEND_CANN_PACKAGE_PATH}/lib64/libnnopbase.so
35+ ${ASCEND_CANN_PACKAGE_PATH}/lib64/libopapi.so
36+ ${ASCEND_CANN_PACKAGE_PATH}/lib64/libascend_dump.so
37+ ${ASCEND_CANN_PACKAGE_PATH}/lib64/libc_sec.so)
@@ -0,0 +1,79 @@
1+# 3_save_exception_info
Z

example / 5_performance / adump目录下的README没有同步修改, 需要增加样例3的索引

likedislike
yring_8
8月6日 评论:
2+ 
3+## 描述
4+ 
5+本用例展示了在算子执行场景下,如何组合使用 `acldumpGetExceptionInfoPath``acldumpSaveExceptionInfo` 两个接口,将自定义的 tensor 数据主动落盘到 Adump 工具的 Exception Dump 路径下。
6+ 
7+场景说明:部分组件或框架在算子异常时存在落盘自定义数据的诉求。本样例通过 `acl.json` 中的 `dump_scene=aic_err_brief_dump` 使能 Exception Dump,先跑通一个正常的 aclnnAdd 算子,随后:
8+ 
9+1. 调用 `acldumpGetExceptionInfoPath` 查询 Exception Dump 的落盘根路径(带 deviceId);
10+2. 构造 `acldumpTensorInfo`(复用算子的 device 地址、shape、dataType),调用 `acldumpSaveExceptionInfo` 将 tensor 数据落盘到该路径下,`userTag` 保存进 Dump 文件 proto 头的 OpAttr 中。
11+ 
12+> 说明:`fileName` 为相对路径(不能为空、不能包含 `..`),最终落盘位置限定在 Exception Dump 根路径之内;为避免重复运行时覆盖已有文件,落盘文件名会在 `fileName` 基础上自动追加 `.custom.{timestamp}` 后缀(`timestamp` 为毫秒级时间戳),例如传入 `save_exception_info`,实际文件名形如 `save_exception_info.custom.20260721153012345`。调用前需确保已使能 Exception Dump,否则接口返回失败。
13+>
14+> 说明:本接口直接以 `tensorAddr` 作为 Device 上的数据地址读取数据,因此样例中 `addrType` 传入 `ACL_DUMP_ADDR_RAW`、`placement` 传入 `ACL_DUMP_PLACEMENT_DEVICE`。
15+ 
16+## 产品支持情况
17+ 
18+本样例支持以下产品:
19+ 
20+| 产品 | 是否支持 |
21+| --- | --- |
22+| Ascend 950PR/Ascend 950DT | √ |
23+| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
24+| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
25+ 
26+## 编译运行
27+ 
28+环境安装详情以及运行详情请见example目录下的[README](../../../README.md)。
29+ 
30+运行步骤如下:
31+ 
32+```bash
33+# ${install_root} 替换为 CANN 安装根目录,默认安装在`/usr/local/Ascend`目录
34+source ${install_root}/cann/set_env.sh
35+ 
36+# 自动识别 SOC_VERSION 和 ASCENDC_CMAKE_DIR
37+source ${git_clone_path}/example/set_sample_env.sh
38+ 
39+# 编译运行
40+bash run.sh
41+```
42+ 
43+## CANN RUNTIME API
44+ 
45+在该sample中,涉及的关键功能点及其关键接口,如下所示:
46+ 
47+- 初始化
48+ - 调用aclInit接口初始化AscendCL配置(通过acl.json使能Exception Dump)。
49+ - 调用aclFinalize接口实现AscendCL去初始化。
50+- Exception Dump
51+ - 调用acldumpGetExceptionInfoPath接口查询Exception Dump的落盘根路径。
52+ - 调用acldumpSaveExceptionInfo接口将自定义tensor数据落盘到Exception Dump路径下,userTag写入proto头OpAttr。
53+- Device管理
54+ - 调用aclrtSetDevice/aclrtResetDeviceForce接口管理Device。
55+- Stream管理
56+ - 调用aclrtCreateStream/aclrtSynchronizeStream/aclrtDestroyStream接口管理Stream。
57+- 内存管理
58+ - 调用aclrtMalloc/aclrtFree接口申请、释放Device内存。
59+- 数据传输
60+ - 调用aclrtMemcpy接口实现数据传输。
61+ 
62+## 本示例新增覆盖
63+ 
64+- `acldumpGetExceptionInfoPath`:查询 Exception Dump 落盘根路径。
65+- `acldumpSaveExceptionInfo`:将自定义 tensor 数据主动落盘到 Exception Dump 路径根路径下,并通过 userTag 保存附加维测信息。
66+ 
67+## 示例输出
68+ 
69+```text
70+[INFO] acldumpGetExceptionInfoPath success, exception dump path is: .../extra-info/data-dump/0/
71+[INFO] acldumpSaveExceptionInfo success, data has been saved under exception dump path: .../extra-info/data-dump/0/
72+[INFO] result[0] is: 1.000000
73+...
74+[INFO] Run the save_exception_info sample successfully.
75+```
76+ 
77+## 已知issue
78+ 
79+ 暂无
@@ -0,0 +1,79 @@
1+# 3_save_exception_info
2+ 
3+## Description
4+ 
5+This example demonstrates how to combine the `acldumpGetExceptionInfoPath` and `acldumpSaveExceptionInfo` interfaces to actively save custom tensor data to the Adump Exception Dump path during operator execution.
6+ 
7+Background: some components or frameworks need to save custom data when an operator exception occurs. This sample enables Exception Dump via `dump_scene=aic_err_brief_dump` in `acl.json`, first runs a normal aclnnAdd operator, and then:
8+ 
9+1. Calls `acldumpGetExceptionInfoPath` to query the Exception Dump root path (with deviceId);
10+2. Builds `acldumpTensorInfo` (reusing the operator's device addresses, shapes, and data types) and calls `acldumpSaveExceptionInfo` to save tensor data under that path. The `userTag` is stored in the OpAttr of the dump file proto header.
11+ 
12+> Note: `fileName` is a relative path (must not be empty or contain a `..` segment); the final location is confined within the Exception Dump root path. To avoid overwriting existing files on repeated runs, a `.custom.{timestamp}` suffix (`timestamp` is a millisecond-level timestamp) is appended to `fileName` for the on-disk filename, e.g. `save_exception_info` becomes `save_exception_info.custom.20260721153012345`. Exception Dump must be enabled before calling, otherwise the interface returns failure.
13+>
14+> Note: this interface reads data by using `tensorAddr` directly as the device data address, so the sample passes `ACL_DUMP_ADDR_RAW` as `addrType` and `ACL_DUMP_PLACEMENT_DEVICE` as `placement`.
15+ 
16+## Product Support
17+ 
18+This sample supports the following products:
19+ 
20+| Product | Supported |
21+| --- | --- |
22+| Ascend 950PR/Ascend 950DT | Yes |
23+| Atlas A3 Training Series Products/Atlas A3 Inference Series Products | Yes |
24+| Atlas A2 Training Series Products/Atlas A2 Inference Series Products | Yes |
25+ 
26+## Build and Run
27+ 
28+For environment installation details and runtime details, see [README](../../../README_en.md) in the example directory.
29+ 
30+Follow the steps below to run:
31+ 
32+```bash
33+# Replace ${install_root} with the CANN installation root directory, which is installed in `/usr/local/Ascend` by default
34+source ${install_root}/cann/set_env.sh
35+ 
36+# Automatically identify SOC_VERSION and ASCENDC_CMAKE_DIR.
37+source ${git_clone_path}/example/set_sample_env.sh
38+ 
39+# Build and run
40+bash run.sh
41+```
42+ 
43+## CANN RUNTIME API
44+ 
45+In this sample, the key functional points and their key interfaces are as follows:
46+ 
47+- Initialization
48+ - Call the aclInit interface to initialize AscendCL configuration (Exception Dump enabled via acl.json).
49+ - Call the aclFinalize interface to deinitialize AscendCL.
50+- Exception Dump
51+ - Call the acldumpGetExceptionInfoPath interface to query the Exception Dump root path.
52+ - Call the acldumpSaveExceptionInfo interface to save custom tensor data under the Exception Dump path, storing userTag in the proto header OpAttr.
53+- Device Management
54+ - Call aclrtSetDevice/aclrtResetDeviceForce interfaces to manage the Device.
55+- Stream Management
56+ - Call aclrtCreateStream/aclrtSynchronizeStream/aclrtDestroyStream interfaces to manage the Stream.
57+- Memory Management
58+ - Call aclrtMalloc/aclrtFree interfaces to allocate and free Device memory.
59+- Data Transfer
60+ - Call the aclrtMemcpy interface to transfer data.
61+ 
62+## Additional Coverage in This Sample
63+ 
64+- `acldumpGetExceptionInfoPath`: query the Exception Dump root path.
65+- `acldumpSaveExceptionInfo`: actively save custom tensor data under the Exception Dump path, with extra info stored via userTag.
66+ 
67+## Sample Output
68+ 
69+```text
70+[INFO] acldumpGetExceptionInfoPath success, exception dump path is: .../extra-info/data-dump/0/
71+[INFO] acldumpSaveExceptionInfo success, data has been saved under exception dump path: .../extra-info/data-dump/0/
72+[INFO] result[0] is: 1.000000
73+...
74+[INFO] Run the save_exception_info sample successfully.
75+```
76+ 
77+## Known Issues
78+ 
79+ None
@@ -0,0 +1,6 @@
1+{
2+ "dump": {
3+ "dump_path": "./",
4+ "dump_scene": "aic_err_brief_dump"
5+ }
6+}
@@ -0,0 +1,149 @@
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 <iostream>
11+#include <vector>
12+#include "securec.h"
13+#include "acl/acl.h"
14+#include "acl/acl_dump.h"
15+#include "aclnnop/aclnn_add.h"
16+#include "utils.h"
17+#include "../adump_tensor_utils.h"
18+ 
19+using namespace std;
20+ 
21+namespace {
22+// 将 shape 填充进 acldumpTensorInfo 的定长数组,并设置有效维度数
23+void FillTensorInfo(acldumpTensorInfo &info, acldumpTensorType type, void *deviceAddr,
24+ const std::vector<int64_t> &shape, int32_t dataType, size_t byteSize)
25+{
26+ (void)memset_s(&info, sizeof(info), 0, sizeof(info));
27+ info.type = type;
28+ info.tensorSize = byteSize;
29+ info.format = aclFormat::ACL_FORMAT_ND;
30+ info.dataType = dataType;
31+ info.tensorAddr = static_cast<int64_t *>(deviceAddr);
32+ // 本接口直接以 tensorAddr 作为 Device 上的数据地址读取数据,因此地址类型为裸地址、数据位于 Device
33+ info.addrType = ACL_DUMP_ADDR_RAW;
34+ info.placement = ACL_DUMP_PLACEMENT_DEVICE;
35+ info.argsOffset = 0;
36+ info.shapeNum = static_cast<uint32_t>(shape.size());
37+ info.originShapeNum = static_cast<uint32_t>(shape.size());
38+ for (size_t i = 0; i < shape.size() && i < ACL_DUMP_MAX_SHAPE_NUM; ++i) {
39+ info.shape[i] = static_cast<uint64_t>(shape[i]);
40+ info.originShape[i] = static_cast<uint64_t>(shape[i]);
41+ }
42+}
43+} // namespace
44+ 
45+int main()
46+{
47+ // The device id
48+ int32_t deviceId = 0;
49+ // The dump configuration path (enables aic_err_brief_dump exception dump)
50+ const char *dumpCfgPath = "./acl.json";
51+ aclrtStream stream = nullptr;
52+ 
53+ // 1. AscendCL Init(加载开启 Exception Dump 的配置)
54+ CHECK_ERROR(adump::InitRuntime(deviceId, &stream, dumpCfgPath));
55+ 
56+ // 2. 查询 Exception Dump 落盘根路径(带 deviceId,自定义数据将落到此目录下)
57+ char excDumpPath[ACL_DUMP_MAX_FILE_PATH_LENGTH] = {0};
58+ if (acldumpGetExceptionInfoPath(excDumpPath, sizeof(excDumpPath)) == ACL_SUCCESS) {
59+ INFO_LOG("acldumpGetExceptionInfoPath success, exception dump path is: %s", excDumpPath);
60+ } else {
61+ ERROR_LOG("acldumpGetExceptionInfoPath failed, exception dump may not be enabled.");
62+ (void)aclrtDestroyStream(stream);
63+ (void)aclrtResetDeviceForce(deviceId);
64+ (void)aclFinalize();
65+ return -1;
66+ }
67+ 
68+ // 3. Create input and output(Custom Construction)
69+ std::vector<int64_t> selfShape{4, 2};
70+ std::vector<int64_t> otherShape{4, 2};
71+ std::vector<int64_t> outShape{4, 2};
72+ void *selfDeviceAddr = nullptr;
73+ void *otherDeviceAddr = nullptr;
74+ void *outDeviceAddr = nullptr;
75+ aclTensor *self = nullptr;
76+ aclTensor *other = nullptr;
77+ aclScalar *alpha = nullptr;
78+ aclTensor *out = nullptr;
79+ std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
80+ std::vector<float> otherHostData = {1, 1, 1, 2, 2, 2, 3, 3};
81+ std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0};
82+ 
83+ float alphaValue = 1.0f;
84+ CHECK_ERROR(adump::CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self));
85+ CHECK_ERROR(adump::CreateAclTensor(otherHostData, otherShape, &otherDeviceAddr, aclDataType::ACL_FLOAT, &other));
86+ alpha = aclCreateScalar(&alphaValue, aclDataType::ACL_FLOAT);
87+ if (alpha == nullptr) {
88+ ERROR_LOG("Create alpha Scalar failed.");
89+ adump::DestroyTensorResources(self, other, alpha, out);
90+ (void)aclrtDestroyStream(stream);
91+ (void)aclrtResetDeviceForce(deviceId);
92+ (void)aclFinalize();
93+ return -1;
94+ }
95+ CHECK_ERROR(adump::CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out));
96+ 
97+ // 4. Call the CANN operator library API(Custom Implementation) —— 跑通一个正常算子
98+ uint64_t workspaceSize = 0;
99+ aclOpExecutor *executor;
100+ CHECK_ERROR(aclnnAddGetWorkspaceSize(self, other, alpha, out, &workspaceSize, &executor));
101+ void *workspaceAddr = nullptr;
102+ if (workspaceSize > 0lu) {
103+ CHECK_ERROR(aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST));
104+ }
105+ CHECK_ERROR(aclnnAdd(workspaceAddr, workspaceSize, executor, stream));
106+ CHECK_ERROR(aclrtSynchronizeStream(stream));
107+ 
108+ // 5. 组合调用 acldumpSaveExceptionInfo,将算子的 tensor 主动落盘到 Exception Dump 路径下
109+ std::vector<acldumpTensorInfo> tensors(3);
110+ const size_t elemBytes = static_cast<size_t>(adump::GetShapeSize(selfShape)) * sizeof(float);
111+ FillTensorInfo(tensors[0], ACL_DUMP_TENSOR_INPUT, selfDeviceAddr, selfShape,
112+ static_cast<int32_t>(aclDataType::ACL_FLOAT), elemBytes);
113+ FillTensorInfo(tensors[1], ACL_DUMP_TENSOR_INPUT, otherDeviceAddr, otherShape,
114+ static_cast<int32_t>(aclDataType::ACL_FLOAT), elemBytes);
115+ FillTensorInfo(tensors[2], ACL_DUMP_TENSOR_OUTPUT, outDeviceAddr, outShape,
116+ static_cast<int32_t>(aclDataType::ACL_FLOAT), elemBytes);
117+ 
118+ const char *userTag = "component=demo;stage=forward;note=save_exception_info_example";
119+ aclError saveRet = acldumpSaveExceptionInfo("save_exception_info", userTag, tensors.data(), tensors.size());
120+ if (saveRet == ACL_SUCCESS) {
121+ INFO_LOG("acldumpSaveExceptionInfo success, data has been saved under exception dump path: %s", excDumpPath);
122+ } else {
123+ WARN_LOG("acldumpSaveExceptionInfo failed, ret=%d. Make sure exception dump is enabled.", saveRet);
124+ }
125+ 
126+ // 5. 校验算子结果
127+ auto size = adump::GetShapeSize(outShape);
128+ std::vector<float> resultData(size, 0);
129+ CHECK_ERROR(aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
130+ size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST));
131+ for (int64_t i = 0; i < size; i++) {
132+ INFO_LOG("result[%ld] is: %f", i, resultData[i]);
133+ }
134+ 
135+ // 6. Release the resources(Custom Destruction)
136+ adump::DestroyTensorResources(self, other, alpha, out);
137+ CHECK_ERROR(aclrtFree(selfDeviceAddr));
138+ CHECK_ERROR(aclrtFree(otherDeviceAddr));
139+ CHECK_ERROR(aclrtFree(outDeviceAddr));
140+ if (workspaceSize > 0lu) {
141+ CHECK_ERROR(aclrtFree(workspaceAddr));
142+ }
143+ 
144+ CHECK_ERROR(aclrtDestroyStream(stream));
145+ CHECK_ERROR(aclrtResetDeviceForce(deviceId));
146+ CHECK_ERROR(aclFinalize());
147+ INFO_LOG("Run the save_exception_info sample successfully.");
148+ return 0;
149+}
@@ -0,0 +1,25 @@
1+#!/bin/bash
2+# -----------------------------------------------------------------------------------------------------------
3+# Copyright (c) 2025 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# -----------------------------------------------------------------------------------------------------------
11+ 
12+set -euo pipefail
13+ 
14+_ASCEND_INSTALL_PATH="${ASCEND_INSTALL_PATH}"
15+source "${_ASCEND_INSTALL_PATH}/bin/setenv.bash"
16+ 
17+rm -rf build
18+mkdir -p build
19+cmake -B build \
20+ -DASCEND_CANN_PACKAGE_PATH="${_ASCEND_INSTALL_PATH}"
21+cmake --build build -j
22+cmake --install build
23+ 
24+file_path=output_msg.txt
25+./build/main | tee "${file_path}"
@@ -1,9 +1,10 @@
1# adump1# adump
2 2 
3-`adump` 目录聚焦 Dump 相关能力,当前按“参数Dump -> 回调Dump -> 配置式Dump”递进组织:3+`adump` 目录聚焦 Dump 相关能力,当前按“参数Dump -> 回调Dump -> 配置式Dump -> 异常Dump”递进组织:
4 4 
5## 样例列表5## 样例列表
6 6 
7- [0_adump_args](./0_adump_args/README.md):使用 `aclopStartDumpArgs` / `aclopStopDumpArgs` 对单算子参数进行 Dump,并查询当前 Dump 输出路径。7- [0_adump_args](./0_adump_args/README.md):使用 `aclopStartDumpArgs` / `aclopStopDumpArgs` 对单算子参数进行 Dump,并查询当前 Dump 输出路径。
8- [1_adump_callback](./1_adump_callback/README.md):使用 `acldumpRegCallback` / `acldumpUnregCallback` 通过回调接收 Dump 数据,并演示 `acldumpChunk` 的基础解析。8- [1_adump_callback](./1_adump_callback/README.md):使用 `acldumpRegCallback` / `acldumpUnregCallback` 通过回调接收 Dump 数据,并演示 `acldumpChunk` 的基础解析。
9- [2_model_dump_config](./2_model_dump_config/README.md):使用 `aclmdlInitDump` / `aclmdlSetDump` / `acldumpGetPath` / `aclmdlFinalizeDump` 演示配置式 Dump。9- [2_model_dump_config](./2_model_dump_config/README.md):使用 `aclmdlInitDump` / `aclmdlSetDump` / `acldumpGetPath` / `aclmdlFinalizeDump` 演示配置式 Dump。
10+- [3_save_exception_info](./3_save_exception_info/README.md):使用 `acldumpGetExceptionInfoPath` / `acldumpSaveExceptionInfo` 将自定义 tensor 数据主动落盘到 Exception Dump 路径下。
@@ -1,9 +1,10 @@
1# adump1# adump
2 2 
3-The `adump` directory focuses on Dump-related capabilities, currently organized progressively as "parameter Dump -> callback Dump -> configuration-based Dump":3+The `adump` directory focuses on Dump-related capabilities, currently organized progressively as "parameter Dump -> callback Dump -> configuration-based Dump -> exception Dump":
4 4 
5## Sample List5## Sample List
6 6 
7- [0_adump_args](./0_adump_args/README_en.md): Use `aclopStartDumpArgs` / `aclopStopDumpArgs` to dump single operator parameters and query the current Dump output path.7- [0_adump_args](./0_adump_args/README_en.md): Use `aclopStartDumpArgs` / `aclopStopDumpArgs` to dump single operator parameters and query the current Dump output path.
8- [1_adump_callback](./1_adump_callback/README_en.md): Use `acldumpRegCallback` / `acldumpUnregCallback` to receive Dump data through a callback and demonstrate basic parsing of `acldumpChunk`.8- [1_adump_callback](./1_adump_callback/README_en.md): Use `acldumpRegCallback` / `acldumpUnregCallback` to receive Dump data through a callback and demonstrate basic parsing of `acldumpChunk`.
9-- [2_model_dump_config](./2_model_dump_config/README_en.md): Use `aclmdlInitDump` / `aclmdlSetDump` / `acldumpGetPath` / `aclmdlFinalizeDump` to demonstrate configuration-based Dump.9+- [2_model_dump_config](./2_model_dump_config/README_en.md): Use `aclmdlInitDump` / `aclmdlSetDump` / `acldumpGetPath` / `aclmdlFinalizeDump` to demonstrate configuration-based Dump.
10+- [3_save_exception_info](./3_save_exception_info/README_en.md): Use `acldumpGetExceptionInfoPath` / `acldumpSaveExceptionInfo` to actively save custom tensor data to the Exception Dump path.
@@ -15,8 +15,10 @@
15 15 
16#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER))16#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER))
17#define ACL_DUMP_API __declspec(dllexport)17#define ACL_DUMP_API __declspec(dllexport)
18+#define ACL_DUMP_WEAK
18#else19#else
19#define ACL_DUMP_API __attribute__((visibility("default")))20#define ACL_DUMP_API __attribute__((visibility("default")))
21+#define ACL_DUMP_WEAK __attribute__((weak))
20#endif22#endif
21 23 
22#ifdef __cplusplus24#ifdef __cplusplus
@@ -25,12 +27,12 @@ extern "C" {
25 27 
26#define ACL_DUMP_MAX_FILE_PATH_LENGTH 409628#define ACL_DUMP_MAX_FILE_PATH_LENGTH 4096
27typedef struct acldumpChunk {29typedef struct acldumpChunk {
28- char fileName[ACL_DUMP_MAX_FILE_PATH_LENGTH]; // file name, absolute path30+ char fileName[ACL_DUMP_MAX_FILE_PATH_LENGTH]; // name of the dump data file to be written, absolute path
29- uint32_t bufLen; // dataBuf length31+ uint32_t bufLen; // length of dataBuf, in bytes
30- uint32_t isLastChunk; // is last chunk. 0: not 1: yes32+ uint32_t isLastChunk; // whether it is the last chunk. 0: no, 1: yes
31- int64_t offset; // Offset in file. -1: append write33+ int64_t offset; // offset of the content in the dump data file. -1: append write
32- int32_t flag; // flag34+ int32_t flag; // reserved flag of the dump data, no flag is defined currently
33- uint8_t dataBuf[0]; // data buffer35+ uint8_t dataBuf[0]; // memory address of the dump data
34} acldumpChunk;36} acldumpChunk;
35 37 
36ACL_DUMP_API aclError acldumpRegCallback(int32_t (*const messageCallback)(const acldumpChunk*, int32_t), int32_t flag);38ACL_DUMP_API aclError acldumpRegCallback(int32_t (*const messageCallback)(const acldumpChunk*, int32_t), int32_t flag);
@@ -63,10 +65,10 @@ ACL_FUNC_VISIBILITY aclError aclopStopDumpArgs(uint32_t dumpType);
63 65 
64typedef enum acldumpType {66typedef enum acldumpType {
65 AIC_ERR_BRIEF_DUMP = 1, // lite exception dump67 AIC_ERR_BRIEF_DUMP = 1, // lite exception dump
66- AIC_ERR_NORM_DUMP = 2, // normal exception dump68+ AIC_ERR_NORM_DUMP = 2, // normal exception dump, dumps shape/data type/format/attributes additionally
67- AIC_ERR_DETAIL_DUMP = 3, // coredump mode69+ AIC_ERR_DETAIL_DUMP = 3, // npu coredump dump, dumps AI Core internal memory, registers and call stack additionally
68- DATA_DUMP = 4, // tensor data dump70+ DATA_DUMP = 4, // model dump or single operator dump
69- OVERFLOW_DUMP = 5 // overflow dump71+ OVERFLOW_DUMP = 5 // overflow operator dump
70} acldumpType;72} acldumpType;
71 73 
72/**74/**
@@ -80,6 +82,81 @@ typedef enum acldumpType {
80 */82 */
81ACL_FUNC_VISIBILITY const char* acldumpGetPath(acldumpType dumpType);83ACL_FUNC_VISIBILITY const char* acldumpGetPath(acldumpType dumpType);
82 84 
85+#define ACL_DUMP_MAX_SHAPE_NUM 25
86+ 
87+typedef enum acldumpTensorType {
88+ ACL_DUMP_TENSOR_INPUT = 0, // input tensor
89+ ACL_DUMP_TENSOR_OUTPUT, // output tensor
90+ ACL_DUMP_TENSOR_WORKSPACE // workspace tensor
91+} acldumpTensorType;
92+ 
93+typedef enum acldumpTensorAddressType {
94+ ACL_DUMP_ADDR_PTR = 0, // address is a level-2 address, one dereference is needed for the data address
95+ ACL_DUMP_ADDR_PTR_PTR, // address is a level-3 address, two dereferences are needed for the data address
96+ ACL_DUMP_ADDR_RAW // address is a raw address, it is the data address itself
97+} acldumpTensorAddressType;
98+ 
99+typedef enum acldumpTensorPlacement {
100+ ACL_DUMP_PLACEMENT_DEVICE = 0, // tensor is placed on device
101+ ACL_DUMP_PLACEMENT_HOST, // tensor is placed on host
102+ ACL_DUMP_PLACEMENT_END // reserved boundary of this enumeration, not a valid placement
103+} acldumpTensorPlacement;
104+ 
105+typedef struct acldumpTensorInfo {
106+ acldumpTensorType type; // tensor type
107+ size_t tensorSize; // tensor size, in bytes
108+ int32_t format; // tensor format
109+ int32_t dataType; // tensor data type
110+ int64_t* tensorAddr; // tensor address
111+ acldumpTensorAddressType addrType; // tensor address type
112+ acldumpTensorPlacement placement; // placement of the tensor data
113+ uint32_t argsOffset; // offset of the tensor within the operator args
114+ uint32_t shapeNum; // valid dim count of shape, <= ACL_DUMP_MAX_SHAPE_NUM
115+ uint32_t originShapeNum; // valid dim count of originShape, <= ACL_DUMP_MAX_SHAPE_NUM
116+ uint64_t shape[ACL_DUMP_MAX_SHAPE_NUM]; // dim array of the tensor shape
117+ uint64_t originShape[ACL_DUMP_MAX_SHAPE_NUM]; // dim array of the tensor originShape
118+} acldumpTensorInfo;
119+ 
120+/**
121+ * @ingroup AscendCL
122+ * @brief Save custom exception information (tensors) to the Exception Dump path.
123+ * @attention It is implemented only on platforms that support Exception Dump, and Exception Dump must be
124+ * enabled before this function is called. A ".custom.{timestamp}" suffix, in which timestamp is
125+ * a millisecond-level timestamp, is appended to fileName on disk (e.g. "info" ->
126+ * "info.custom.20260721153012345") to avoid overwriting existing files on repeated calls.
127+ * @param fileName [IN] Target file name, a relative path saved under the Exception Dump root path.
128+ * Must not be NULL, must not be empty, and must not contain a ".." path segment.
129+ * @param userTag [IN] User custom tag written into the dump file header. May be NULL.
130+ * @param tensors [IN] Tensors to be saved. Must not be NULL, and must point to an array holding at
131+ * least tensorCount elements. Each element's shapeNum/originShapeNum must not
132+ * exceed ACL_DUMP_MAX_SHAPE_NUM, tensorAddr must be a non-NULL raw device data
133+ * address of the tensor, that is, addrType ACL_DUMP_ADDR_RAW and placement
134+ * ACL_DUMP_PLACEMENT_DEVICE, and tensorSize must be greater than 0.
135+ * @param tensorCount [IN] Count of tensors in the tensors array, must be greater than 0. The caller must
136+ * guarantee it matches the actual array length.
137+ * @retval ACL_SUCCESS The function is successfully executed.
138+ * @retval ACL_ERROR_INVALID_PARAM Invalid fileName/tensors/tensorCount, a tensor with a NULL tensorAddr or a
139+ * zero tensorSize, or shapeNum/originShapeNum exceeds the limit.
140+ * @retval OtherValues Failure (e.g. Exception Dump not enabled).
141+ */
142+ACL_DUMP_WEAK ACL_FUNC_VISIBILITY aclError acldumpSaveExceptionInfo(
143+ const char* fileName, const char* userTag, const acldumpTensorInfo* tensors, size_t tensorCount);
144+ 
145+/**
146+ * @ingroup AscendCL
147+ * @brief Get the Exception Dump root path (i.e. <dumpPath>/extra-info/data-dump/<deviceId>/).
148+ * @attention It is implemented only on platforms that support Exception Dump, and Exception Dump must be
149+ * enabled before this function is called.
150+ * @param path [OUT] Character array to receive the path, allocated by the caller in advance. On success a
151+ * '\0'-terminated path is written into it. ACL_DUMP_MAX_FILE_PATH_LENGTH bytes are
152+ * recommended.
153+ * @param maxLen [IN] Memory size of the path parameter, in bytes. Must be greater than 1 and large enough
154+ * to hold the path plus the terminating '\0'.
155+ * @retval ACL_SUCCESS The function is successfully executed.
156+ * @retval OtherValues Failure (e.g. Exception Dump not enabled, or buffer too small).
157+ */
158+ACL_DUMP_WEAK ACL_FUNC_VISIBILITY aclError acldumpGetExceptionInfoPath(char* path, size_t maxLen);
159+ 
83#ifdef __cplusplus160#ifdef __cplusplus
84}161}
85#endif162#endif
@@ -48,4 +48,31 @@ const char* acldumpGetPath(acldumpType dumpType)
48{48{
49 UNUSED(dumpType);49 UNUSED(dumpType);
50 return nullptr;50 return nullptr;
51-}51+}
52+ 
53+/**
54+ * @ingroup AscendCL
55+ * @brief Save custom exception info to the Exception Dump path. Not supported on this platform.
56+ * @retval ACL_ERROR_FAILURE Not supported.
57+ */
58+aclError acldumpSaveExceptionInfo(const char *fileName, const char *userTag,
59+ const acldumpTensorInfo *tensors, size_t tensorCount)
60+{
61+ UNUSED(fileName);
62+ UNUSED(userTag);
63+ UNUSED(tensors);
64+ UNUSED(tensorCount);
65+ return ACL_ERROR_FAILURE;
66+}
67+ 
68+/**
69+ * @ingroup AscendCL
70+ * @brief Get the Exception Dump root path. Not supported on this platform.
71+ * @retval ACL_ERROR_FAILURE Not supported.
72+ */
73+aclError acldumpGetExceptionInfoPath(char *path, size_t maxLen)
74+{
75+ UNUSED(path);
76+ UNUSED(maxLen);
77+ return ACL_ERROR_FAILURE;
78+}
@@ -115,7 +115,7 @@ namespace Adx {
115 do { \115 do { \
116 IDE_LOGE("[%s] %s failed. Reason: %s.", ADUMP_TO_CSTR(funcName), ADUMP_TO_CSTR(funcName), ADUMP_TO_CSTR(reason)); \116 IDE_LOGE("[%s] %s failed. Reason: %s.", ADUMP_TO_CSTR(funcName), ADUMP_TO_CSTR(funcName), ADUMP_TO_CSTR(reason)); \
117 ADUMP_INPUT_ERROR("EP0008", std::vector<std::string>({"func", "reason"}), \117 ADUMP_INPUT_ERROR("EP0008", std::vector<std::string>({"func", "reason"}), \
118- std::vector<std::string>({funcName, reason})); \118+ std::vector<std::string>({std::string(funcName), std::string(reason)})); \
119 } while (0)119 } while (0)
120 120 
121// EP0001 Reasons - Configuration item problems121// EP0001 Reasons - Configuration item problems
@@ -165,13 +165,20 @@ constexpr const char* ADUMP_REASON_FMT_ITEM_VALUE_CANNOT_SET_WHEN_ITEM_VALUE =
165// EP0006 Reasons - Invalid argument problems165// EP0006 Reasons - Invalid argument problems
166constexpr const char* ADUMP_REASON_RESERVED_PARAM_MUST_EQUAL = "The parameter is reserved and can only be %s";166constexpr const char* ADUMP_REASON_RESERVED_PARAM_MUST_EQUAL = "The parameter is reserved and can only be %s";
167constexpr const char* ADUMP_REASON_PARAM_PATH_EMPTY = "The parameter is a path and cannot be empty";167constexpr const char* ADUMP_REASON_PARAM_PATH_EMPTY = "The parameter is a path and cannot be empty";
168+constexpr const char* ADUMP_REASON_PARAM_PATH_HAS_PARENT_DIR =
169+ "The parameter is a relative path and cannot contain '..' segment";
168constexpr const char* ADUMP_REASON_PARAM_PATH_CREATE_DIR_ERROR = 170constexpr const char* ADUMP_REASON_PARAM_PATH_CREATE_DIR_ERROR =
169 "The parameter is a path and the path fails to be created. Error: %s";171 "The parameter is a path and the path fails to be created. Error: %s";
170-constexpr const char* ADUMP_REASON_PARAM_PATH_NOT_DIRECTORY = 172+constexpr const char* ADUMP_REASON_PARAM_PATH_NOT_DIRECTORY =
171 "The parameter is not a directory path";173 "The parameter is not a directory path";
174+constexpr const char* ADUMP_REASON_PARAM_MUST_BE_GREATER_THAN = "The parameter must be greater than %s";
175+constexpr const char* ADUMP_REASON_BUFFER_SIZE_NOT_ENOUGH = "The buffer size %s is not enough for the result size %s";
176+constexpr const char* ADUMP_REASON_PARAM_VALUE_EXCEED_LIMIT = "The value %s exceeds the maximum limit of %s";
177+constexpr const char* ADUMP_REASON_PARAM_VALUE_NOT_SUPPORTED = "The value %s is not supported, it must be %s";
172 178 
173// EP0008 Reasons - Call API sequence179// EP0008 Reasons - Call API sequence
174constexpr const char* ADUMP_REASON_API_CALLED_REPEATEDLY = "This API cannot be called repeatedly";180constexpr const char* ADUMP_REASON_API_CALLED_REPEATEDLY = "This API cannot be called repeatedly";
181+constexpr const char* ADUMP_REASON_EXCEPTION_DUMP_NOT_ENABLED = "Exception Dump must be enabled before %s is called";
175 182 
176constexpr const char* FUNC_NAME_ACL_OP_START_DUMP_ARGS = "aclopStartDumpArgs";183constexpr const char* FUNC_NAME_ACL_OP_START_DUMP_ARGS = "aclopStartDumpArgs";
177constexpr const char* FUNC_ACL_OP_START_DUMP_ARGS_PARAM_PATH = "path";184constexpr const char* FUNC_ACL_OP_START_DUMP_ARGS_PARAM_PATH = "path";
@@ -179,6 +186,13 @@ constexpr const char* FUNC_ACL_OP_START_DUMP_ARGS_PARAM_DUMPTYPE = "dumpType";
179constexpr const char* FUNC_NAME_ACL_DUMP_REG_CALLBACK = "acldumpRegCallback";186constexpr const char* FUNC_NAME_ACL_DUMP_REG_CALLBACK = "acldumpRegCallback";
180constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_CLBK = "messageCallback";187constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_CLBK = "messageCallback";
181constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_FLAG = "flag";188constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_FLAG = "flag";
189+constexpr const char* FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO = "acldumpSaveExceptionInfo";
190+constexpr const char* FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_FILENAME = "fileName";
191+constexpr const char* FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_TENSORS = "tensors";
192+constexpr const char* FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_TENSORCOUNT = "tensorCount";
193+constexpr const char* FUNC_NAME_ACL_DUMP_GET_EXCEPTION_INFO_PATH = "acldumpGetExceptionInfoPath";
194+constexpr const char* FUNC_ACL_DUMP_GET_EXCEPTION_INFO_PATH_PARAM_PATH = "path";
195+constexpr const char* FUNC_ACL_DUMP_GET_EXCEPTION_INFO_PATH_PARAM_MAXLEN = "maxLen";
182} // namespace Adx196} // namespace Adx
183 197 
184#endif198#endif
@@ -17,10 +17,28 @@ namespace Adx {
17namespace {17namespace {
18constexpr char DIRECTORY_SEPARATOR = '/';18constexpr char DIRECTORY_SEPARATOR = '/';
19constexpr char FILE_EXTENSION_CHAR = '.';19constexpr char FILE_EXTENSION_CHAR = '.';
20+constexpr const char *PARENT_DIR = "..";
20 21 
21constexpr mmMode_t DEFAULT_DIR_MODE = M_IRUSR | M_IWUSR | M_IXUSR;22constexpr mmMode_t DEFAULT_DIR_MODE = M_IRUSR | M_IWUSR | M_IXUSR;
22} // namespace23} // namespace
23 24 
25+bool Path::HasParentDirSegment(const std::string &path)
26+{
27+ size_t begin = 0;
28+ while (begin <= path.size()) {
29+ const size_t end = path.find(DIRECTORY_SEPARATOR, begin);
30+ const size_t len = (end == std::string::npos ? path.size() : end) - begin;
31+ if (path.compare(begin, len, PARENT_DIR) == 0) {
32+ return true;
33+ }
34+ if (end == std::string::npos) {
35+ break;
36+ }
37+ begin = end + 1;
38+ }
39+ return false;
40+}
41+ 
24Path &Path::operator = (const std::string &path)42Path &Path::operator = (const std::string &path)
25{43{
26 path_ = path;44 path_ = path;
@@ -175,6 +193,73 @@ const char *Path::GetCString() const
175 return path_.c_str();193 return path_.c_str();
176}194}
177 195 
196+bool Path::BuildFullPathUnderRoot(const std::string &rootPath, const std::string &relativeFile,
197+ std::string &canonicalFile)
198+{
199+ if (rootPath.empty() || relativeFile.empty()) {
200+ IDE_LOGE("rootPath or relativeFile is empty.");
201+ return false;
202+ }
203+ 
204+ if (HasParentDirSegment(relativeFile)) {
205+ IDE_LOGE("relativeFile[%s] contains '..' segment.", relativeFile.c_str());
206+ return false;
207+ }
208+ 
209+ const std::string filePath = Path(rootPath).Concat(relativeFile).GetString();
210+ const std::string baseName = Path(filePath).GetFileName();
211+ 
212+ Path dirPath = Path(filePath).ParentPath();
213+ if (!dirPath.CreateDirectory(true)) {
214+ IDE_LOGE("create directory failed, dirPath=%s.", dirPath.GetCString());
215+ return false;
216+ }
217+ 
218+ if (!dirPath.RealPath()) {
219+ IDE_LOGE("get real path failed, dirPath=%s.", dirPath.GetCString());
220+ return false;
221+ }
222+ 
223+ if (!dirPath.IsDirectory()) {
224+ IDE_LOGE("path is not a directory, dirPath=%s", dirPath.GetCString());
225+ return false;
226+ }
227+ 
228+ Path realRootPath(rootPath);
229+ if (!realRootPath.RealPath()) {
230+ IDE_LOGE("get real path failed, rootPath=%s.", realRootPath.GetCString());
231+ return false;
232+ }
233+ 
234+ if (!IsUnderDirectory(realRootPath.GetString(), dirPath.GetString())) {
235+ IDE_LOGE("resolved dirPath=%s escapes rootPath=%s.", dirPath.GetCString(), realRootPath.GetCString());
236+ return false;
237+ }
238+ 
239+ canonicalFile = dirPath.GetString() + DIRECTORY_SEPARATOR + baseName;
240+ return true;
241+}
242+ 
243+bool Path::IsUnderDirectory(const std::string &realDirPath, const std::string &realSubPath)
244+{
245+ if (realDirPath.empty() || realSubPath.empty()) {
246+ return false;
247+ }
248+ 
249+ // Both paths are already canonical, so a segment-aware prefix match is sufficient.
250+ std::string prefix = realDirPath;
251+ if (prefix.back() != DIRECTORY_SEPARATOR) {
252+ prefix += DIRECTORY_SEPARATOR;
253+ }
254+ 
255+ std::string target = realSubPath;
256+ if (target.back() != DIRECTORY_SEPARATOR) {
257+ target += DIRECTORY_SEPARATOR;
258+ }
259+ 
260+ return target.compare(0, prefix.size(), prefix) == 0;
261+}
262+ 
178void Path::AppendPath(const std::string &path)263void Path::AppendPath(const std::string &path)
179{264{
180 std::string newPath = StrUtils::Trim(path);265 std::string newPath = StrUtils::Trim(path);
@@ -38,6 +38,35 @@ public:
38 bool CreateDirectory(bool recursion = false) const;38 bool CreateDirectory(bool recursion = false) const;
39 std::string GetString() const;39 std::string GetString() const;
40 const char *GetCString() const;40 const char *GetCString() const;
41+ /*
42+ * @brief: 将相对文件 relativeFile 拼接到 rootPath 下,生成规范化的绝对文件路径。处理包括:
43+ * 1) 校验 relativeFile 不含 '..' 路径段(防路径穿越);
44+ * 2) 递归创建父目录;
45+ * 3) 对父目录做 RealPath 解析并校验其确为目录;
46+ * 4) 纵深防御:校验解析后的父目录仍位于 rootPath 之内(防落盘根目录下的软链接指向外部)。
47+ * @param [in] rootPath 根路径(限定的落盘根目录)
48+ * @param [in] relativeFile 相对文件路径(不能为空,不允许包含 '..' 段;前导 '/' 会被 Concat 剥离)
49+ * @param [out] canonicalFile 规范化后的绝对文件路径(父目录已 RealPath 解析)
50+ * @return true: 合法且父目录就绪; false: 入参非法、路径穿越、创建目录失败、父目录非法或逃逸出 rootPath
51+ */
52+ static bool BuildFullPathUnderRoot(const std::string &rootPath, const std::string &relativeFile,
53+ std::string &canonicalFile);
54+ 
55+ /*
56+ * @brief: 判断 realSubPath 是否位于 realDirPath 目录之内(含相等)。两个入参都必须是已 RealPath 解析
57+ * 的规范化绝对路径。按 '/' 路径段比较,避免 /root_evil 被 /root 误判为子路径。
58+ * @param [in] realDirPath 规范化后的目录路径
59+ * @param [in] realSubPath 规范化后的待判断路径
60+ * @return true: realSubPath 在 realDirPath 之内; false: 不在其内或入参为空
61+ */
62+ static bool IsUnderDirectory(const std::string &realDirPath, const std::string &realSubPath);
63+ 
64+ /*
65+ * @brief: 判断相对路径中是否存在 '..' 路径段(按 '/' 分段判断,避免误杀 my..file.bin 这类合法文件名)。
66+ * @param [in] path 待判断的相对路径
67+ * @return true: 存在 '..' 路径段(可能导致路径穿越); false: 不存在
68+ */
69+ static bool HasParentDirSegment(const std::string &path);
41 70 
42private:71private:
43 void AppendPath(const std::string &path);72 void AppendPath(const std::string &path);
@@ -178,42 +178,13 @@ int32_t DumpArgsCallback::DumpExtraTensors()
178 }178 }
179 179 
180 IDE_LOGI("Begin to dump extra tensors. extra tensor size=%u", info_.extraTensorNum);180 IDE_LOGI("Begin to dump extra tensors. extra tensor size=%u", info_.extraTensorNum);
181-
182- std::vector<DumpTensor> inputTensors;
183- std::vector<DumpTensor> outputTensors;
184- std::vector<DumpWorkspace> workspaces;
185- uint32_t baseOffset = static_cast<uint32_t>(tensorBuffer_.size() + workspaces_.size());
186-
187- for (uint32_t i = 0; i < info_.extraTensorNum; ++i) {
188- if (info_.extraTensor[i].tensorAddr == nullptr || info_.extraTensor[i].tensorSize == 0) {
189- IDE_LOGW("Skip null extra tensor[%u], addr=%p, size=%zu.",
190- i, info_.extraTensor[i].tensorAddr, info_.extraTensor[i].tensorSize);
191- continue;
192- }
193- // tensor基于args偏移offset
194- info_.extraTensor[i].argsOffSet = baseOffset + i;
195-
196- RecordDumpLog(StrUtils::Format("[Dump][Exception] exception info dump extra tensor data, "
197- "addr:%p; size:%zu bytes; index:%u(origin:%u); type:%d",
198- info_.extraTensor[i].tensorAddr, info_.extraTensor[i].tensorSize,
199- info_.extraTensor[i].argsOffSet, i, static_cast<int>(info_.extraTensor[i].type)));
200-
201- if (info_.extraTensor[i].type == TensorType::INPUT) {
202- inputTensors.emplace_back(info_.extraTensor[i]);
203- } else if (info_.extraTensor[i].type == TensorType::OUTPUT) {
204- outputTensors.emplace_back(info_.extraTensor[i]);
205- } else if (info_.extraTensor[i].type == TensorType::WORKSPACE) {
206- DumpWorkspace workspace;
207- workspace.addr = info_.extraTensor[i].tensorAddr;
208- workspace.bytes = info_.extraTensor[i].tensorSize;
209- workspace.argsOffset = info_.extraTensor[i].argsOffSet;
210- workspaces.push_back(workspace);
211- }
212- }
213 181 
214- dumpFile_.SetInputTensors(inputTensors);182+ const uint32_t baseOffset = static_cast<uint32_t>(tensorBuffer_.size() + workspaces_.size());
215- dumpFile_.SetOutputTensors(outputTensors);183+ std::vector<TensorInfo> tensors(info_.extraTensor, info_.extraTensor + info_.extraTensorNum);
216- dumpFile_.SetWorkspaces(workspaces);184+ for (uint32_t i = 0; i < info_.extraTensorNum; ++i) {
185+ tensors[i].argsOffSet = baseOffset + i;
186+ }
187+ dumpFile_.SetTensors(tensors, logRecord_);
217 188 
218 IDE_LOGI("End to dump extra tensors.");189 IDE_LOGI("End to dump extra tensors.");
219 return ADUMP_SUCCESS;190 return ADUMP_SUCCESS;
@@ -12,6 +12,7 @@
12#include <sstream>12#include <sstream>
13#include "runtime/mem.h"13#include "runtime/mem.h"
14#include "sys_utils.h"14#include "sys_utils.h"
15+#include "str_utils.h"
15#include "dump_datatype.h"16#include "dump_datatype.h"
16#include "dump_memory.h"17#include "dump_memory.h"
17#include "log/hdc_log.h"18#include "log/hdc_log.h"
@@ -35,6 +36,15 @@ void DumpFile::SetHeader(const std::string &opName)
35 header_.set_op_name(opName);36 header_.set_op_name(opName);
36}37}
37 38 
39+void DumpFile::SetOpAttr(const std::string &name, const std::string &value)
40+{
41+ toolkit::dump::OpAttr attr;
42+ attr.set_name(name);
43+ attr.set_value(value);
44+ header_.mutable_attr()->Add(std::move(attr));
45+ IDE_LOGI("[Set][DumpData] Set op attr, name: %s", name.c_str());
46+}
47+ 
38void DumpFile::SetInputTensors(const std::vector<DumpTensor> &inputTensors)48void DumpFile::SetInputTensors(const std::vector<DumpTensor> &inputTensors)
39{49{
40 for (size_t i = 0U; i < inputTensors.size(); ++i) {50 for (size_t i = 0U; i < inputTensors.size(); ++i) {
@@ -105,6 +115,43 @@ void DumpFile::SetWorkspaces(const std::vector<DumpWorkspace> &workspaces)
105 }115 }
106}116}
107 117 
118+void DumpFile::SetTensors(const std::vector<TensorInfo> &tensors, std::vector<std::string> &record)
119+{
120+ std::vector<DumpTensor> inputTensors;
121+ std::vector<DumpTensor> outputTensors;
122+ std::vector<DumpWorkspace> workspaces;
123+ for (size_t index = 0U; index < tensors.size(); ++index) {
124+ const TensorInfo &tensor = tensors[index];
125+ if (tensor.tensorAddr == nullptr || tensor.tensorSize == 0) {
F
Ffujun198月4日

【严重】【Major】这里把 tensorAddr == nullptrtensorSize == 0 的 tensor 静默跳过;当 tensorCount == 0 或所有 tensor 都无效时,后续 Dump() 会因没有数据直接返回成功,acldumpSaveExceptionInfo 最终报成功但实际没有文件/数据落盘。建议在入口校验 tensorCount > 0 以及每个 tensor 的地址和 size,非法时返回 ACL_ERROR_INVALID_PARAM

likedislike
yring_8
8月4日 评论:
126+ IDE_LOGW("[Set][DumpData] skip null/empty tensor[%zu], addr=%p, size=%zu, type=%d.",
127+ index, tensor.tensorAddr, tensor.tensorSize, static_cast<int32_t>(tensor.type));
128+ continue;
129+ }
130+ 
131+ std::string info = StrUtils::Format(
132+ "[Dump][Exception] exception info dump tensor data, type=%s; index=%zu; shape=%s; format=%s; "
133+ "dtype=%s; address=%p; size=%zu bytes",
134+ DumpDataType::TensorTypeToSerialString(tensor.type).c_str(), index,
135+ StrUtils::ToString(tensor.shape).c_str(),
136+ DumpDataType::FormatToSerialString(tensor.format).c_str(),
137+ DumpDataType::DataTypeToSerialString(tensor.dataType).c_str(),
138+ tensor.tensorAddr, tensor.tensorSize);
139+ IDE_LOGI("%s", info.c_str());
140+ record.emplace_back(info + "\n");
141+ 
142+ if (tensor.type == TensorType::INPUT) {
143+ inputTensors.emplace_back(tensor);
144+ } else if (tensor.type == TensorType::OUTPUT) {
145+ outputTensors.emplace_back(tensor);
146+ } else if (tensor.type == TensorType::WORKSPACE) {
147+ workspaces.emplace_back(tensor.tensorAddr, static_cast<uint64_t>(tensor.tensorSize), tensor.argsOffSet);
148+ }
149+ }
150+ SetInputTensors(inputTensors);
151+ SetOutputTensors(outputTensors);
152+ SetWorkspaces(workspaces);
153+}
154+ 
108#if !defined(ADUMP_SOC_HOST) || ADUMP_SOC_HOST == 1155#if !defined(ADUMP_SOC_HOST) || ADUMP_SOC_HOST == 1
109void DumpFile::SetMc2spaces(const std::vector<DumpWorkspace> &mc2Spaces)156void DumpFile::SetMc2spaces(const std::vector<DumpWorkspace> &mc2Spaces)
110{157{
@@ -26,9 +26,11 @@ public:
26 DumpFile(const uint32_t deviceId, const std::string &filePath) : deviceId_(deviceId),26 DumpFile(const uint32_t deviceId, const std::string &filePath) : deviceId_(deviceId),
27 file_(filePath, M_RDWR | M_CREAT | M_APPEND, M_IRUSR | M_IWUSR, true) {}27 file_(filePath, M_RDWR | M_CREAT | M_APPEND, M_IRUSR | M_IWUSR, true) {}
28 void SetHeader(const std::string &opName);28 void SetHeader(const std::string &opName);
29+ void SetOpAttr(const std::string &name, const std::string &value);
29 void SetInputTensors(const std::vector<DumpTensor> &inputTensors);30 void SetInputTensors(const std::vector<DumpTensor> &inputTensors);
30 void SetOutputTensors(const std::vector<DumpTensor> &outputTensors);31 void SetOutputTensors(const std::vector<DumpTensor> &outputTensors);
31 void SetWorkspaces(const std::vector<DumpWorkspace> &workspaces);32 void SetWorkspaces(const std::vector<DumpWorkspace> &workspaces);
33+ void SetTensors(const std::vector<TensorInfo> &tensors, std::vector<std::string> &record);
32 void SetInputBuffer(const std::vector<InputBuffer> input);34 void SetInputBuffer(const std::vector<InputBuffer> input);
33 void SetTensorBuffer(const std::vector<TensorBuffer> &tensorBuffer);35 void SetTensorBuffer(const std::vector<TensorBuffer> &tensorBuffer);
34 int32_t Dump(std::vector<std::string> &record);36 int32_t Dump(std::vector<std::string> &record);
@@ -107,11 +107,16 @@ bool ExceptionDumper::IsRepeatEnableException(DumpType type, const DumpConfig &d
107 if (dumpStatus != "on") {107 if (dumpStatus != "on") {
108 return false;108 return false;
109 }109 }
110- return GetCoredumpStatus() || GetExceptionStatus() || GetArgsExceptionStatus();110+ return IsEnabledExceptionDump();
111 }111 }
112 return false;112 return false;
113}113}
114 114 
115+bool ExceptionDumper::IsEnabledExceptionDump() const
116+{
117+ return coredumpStatus_ || exceptionStatus_ || argsExceptionStatus_;
118+}
119+ 
115int32_t ExceptionDumper::ExceptionDumperInit(DumpType dumpType, const DumpConfig &dumpConfig)120int32_t ExceptionDumper::ExceptionDumperInit(DumpType dumpType, const DumpConfig &dumpConfig)
116{121{
117 bool status = false;122 bool status = false;
@@ -169,7 +174,7 @@ int32_t ExceptionDumper::DumpException(const rtExceptionInfo &exception)
169 IDE_CTRL_VALUE_WARN(!destructionFlag_, return ADUMP_FAILED, "ExceptionDumper has been destructed.");174 IDE_CTRL_VALUE_WARN(!destructionFlag_, return ADUMP_FAILED, "ExceptionDumper has been destructed.");
170 IDE_CTRL_VALUE_WARN(ExceptionInfoCommon::IsSupportExceptionDump(exception),175 IDE_CTRL_VALUE_WARN(ExceptionInfoCommon::IsSupportExceptionDump(exception),
171 return ADUMP_FAILED, "Exception is not need to dump.");176 return ADUMP_FAILED, "Exception is not need to dump.");
172- IDE_CTRL_VALUE_WARN(coredumpStatus_ || exceptionStatus_ || argsExceptionStatus_, return ADUMP_FAILED,177+ IDE_CTRL_VALUE_WARN(IsEnabledExceptionDump(), return ADUMP_FAILED,
173 "Not enable exception dump.");178 "Not enable exception dump.");
174 std::string dumpPath = CreateDeviceDumpPath(exception.deviceid);179 std::string dumpPath = CreateDeviceDumpPath(exception.deviceid);
175 if (dumpPath.empty()) {180 if (dumpPath.empty()) {
@@ -258,6 +263,53 @@ std::string ExceptionDumper::CreateDeviceDumpPath(uint32_t deviceId) const
258 return CreateDumpPath(deviceDumpPath);263 return CreateDumpPath(deviceDumpPath);
259}264}
260 265 
266+int32_t ExceptionDumper::GetExceptionDumpPath(std::string &path)
267+{
268+ int32_t deviceId = 0;
zhangjie
zhangjiezhangjie8月3日

级别:一般 问题:SaveExceptionInfo 中调用了两次 rtGetDevice:第一次在 GetExceptionDumpPath 内部,第二次在 SaveExceptionInfo 本体中获取 devId 用于构造 DumpFile。 影响:冗余的 runtime 调用增加开销,且两次调用之间理论上可能因设备切换导致 deviceId 不一致(虽然实际场景中同一线程 deviceId 不会变化,但代码逻辑上存在不一致风险)。 修复建议:让 GetExceptionDumpPath 顺带返回 deviceId,或在 SaveExceptionInfo 中复用已获取的 deviceId,避免重复调用 rtGetDevice。

likedislike
yring_8
8月3日 评论:
269+ const rtError_t rtRet = rtGetDevice(&deviceId);
270+ IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE, return ADUMP_FAILED,
271+ "rtGetDevice failed when get the exception root dump path, ret=%d.", static_cast<int32_t>(rtRet));
272+ 
273+ path = CreateDeviceDumpPath(static_cast<uint32_t>(deviceId));
274+ IDE_CTRL_VALUE_FAILED(!path.empty(), return ADUMP_FAILED, "exception dump root path is not ready.");
275+ return ADUMP_SUCCESS;
276+}
277+ 
278+int32_t ExceptionDumper::SaveExceptionInfo(const std::string &fileName, const std::string &userTag,
279+ const std::vector<TensorInfo> &tensors)
280+{
281+ std::string rootPath;
282+ IDE_CTRL_VALUE_FAILED(GetExceptionDumpPath(rootPath) == ADUMP_SUCCESS, return ADUMP_FAILED,
283+ "[SaveExceptionInfo] get exception dump root path failed.");
284+ 
285+ std::string realFilePath;
286+ IDE_CTRL_VALUE_FAILED(Path::BuildFullPathUnderRoot(rootPath, fileName, realFilePath),
287+ return ADUMP_FAILED, "[SaveExceptionInfo] build full file path failed.");
288+ 
289+ realFilePath += ".custom." + SysUtils::GetCurrentTimeWithMillisecond();
290+ 
J
Jjinyingqi8月3日

问题:落盘文件名仅追加毫秒级时间戳,不能保证同一 fileName 的并发或快速连续调用唯一。

  • 严重程度:major
  • 影响:同一毫秒内多次调用会生成相同 realFilePath,而 DumpFile 以追加方式打开文件,多个 dump 记录可能被追加到同一个文件中,导致 dump 文件内容混杂或解析异常。
  • 修改建议:使用 O_EXCL/等价排他创建并在冲突时重试,或在时间戳外追加进程内原子序号、线程标识等唯一后缀,避免依赖毫秒时间戳。
likedislike
yring_8
8月3日 评论:
291+ int32_t devId = 0;
292+ const rtError_t rtRet = rtGetDevice(&devId);
293+ IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE, return ADUMP_FAILED,
294+ "[SaveExceptionInfo] rtGetDevice failed, ret=%d.", static_cast<int32_t>(rtRet));
295+ 
zhangjie
zhangjiezhangjie8月3日

级别:一般 问题:时间戳后缀使用毫秒级 GetCurrentTimeWithMillisecond,若同一毫秒内多次调用 acldumpSaveExceptionInfo 且传入相同 fileName,将产生相同的最终文件路径。由于 DumpFile 以 M_APPEND 模式打开文件,多次调用的数据会被追加写入同一文件。 影响:高频调用场景下可能产生数据混叠,用户难以区分不同次落盘的数据。 修复建议:在时间戳基础上追加进程内自增序号或随机后缀以保证文件名唯一性,或在文档中明确说明同一毫秒内多次调用的行为约束。

likedislike
yring_8
8月3日 评论:
296+ DumpFile dumpFile(static_cast<uint32_t>(devId), realFilePath);
297+ dumpFile.SetHeader(Path(realFilePath).GetFileName());
298+ if (!userTag.empty()) {
299+ dumpFile.SetOpAttr("user_tag", userTag);
300+ }
301+ 
302+ std::vector<std::string> record;
303+ dumpFile.SetTensors(tensors, record);
304+ 
305+ IDE_CTRL_VALUE_FAILED(dumpFile.Dump(record) == ADUMP_SUCCESS, return ADUMP_FAILED,
306+ "[SaveExceptionInfo] dump exception info to file failed, file: %s", realFilePath.c_str());
307+ 
308+ (void)mmChmod(realFilePath.c_str(), M_IRUSR);
309+ IDE_LOGE("[Dump][Exception] dump custom exception to file, file: %s", realFilePath.c_str());
310+ return ADUMP_SUCCESS;
311+}
312+ 
261std::string ExceptionDumper::CreateExtraDumpPath()313std::string ExceptionDumper::CreateExtraDumpPath()
262{314{
263 // Create extra dump path for tensor custom dump data315 // Create extra dump path for tensor custom dump data
@@ -30,14 +30,18 @@ public:
30 inline bool GetCoredumpStatus() const;30 inline bool GetCoredumpStatus() const;
31 void SetDumpPath(const std::string &dumpPath);31 void SetDumpPath(const std::string &dumpPath);
32 std::string CreateExtraDumpPath();32 std::string CreateExtraDumpPath();
33+ std::string CreateDeviceDumpPath(uint32_t deviceId) const;
33 const char* GetExtraDumpCPath() const;34 const char* GetExtraDumpCPath() const;
34 void AddDumpOperator(const OperatorInfo &opInfo);35 void AddDumpOperator(const OperatorInfo &opInfo);
35 void AddDumpOperatorV2(const OperatorInfoV2 &opInfo);36 void AddDumpOperatorV2(const OperatorInfoV2 &opInfo);
36 int32_t DelDumpOperator(uint32_t deviceId, uint32_t streamId);37 int32_t DelDumpOperator(uint32_t deviceId, uint32_t streamId);
37 int32_t DumpException(const rtExceptionInfo &exception);38 int32_t DumpException(const rtExceptionInfo &exception);
39+ int32_t GetExceptionDumpPath(std::string &path);
40+ int32_t SaveExceptionInfo(const std::string &fileName, const std::string &userTag,
41+ const std::vector<TensorInfo> &tensors);
38 void ExceptionModeDowngrade();42 void ExceptionModeDowngrade();
39 bool IsRepeatEnableException(DumpType type, const DumpConfig &dumpConfig);43 bool IsRepeatEnableException(DumpType type, const DumpConfig &dumpConfig);
40- 44+ bool IsEnabledExceptionDump() const;
41 int32_t RegisterExceptionDumpCallback(ExceptionDumpCallback callback);45 int32_t RegisterExceptionDumpCallback(ExceptionDumpCallback callback);
42 int32_t UnregisterExceptionDumpCallback(ExceptionDumpCallback callback);46 int32_t UnregisterExceptionDumpCallback(ExceptionDumpCallback callback);
43 47 
@@ -47,7 +51,6 @@ public:
47 51 
48private:52private:
49 std::string CreateDumpPath(Path &dumpPath) const;53 std::string CreateDumpPath(Path &dumpPath) const;
50- std::string CreateDeviceDumpPath(uint32_t deviceId) const;
51 bool FindExceptionOperator(const rtExceptionInfo &exception, DumpOperator &excOp);54 bool FindExceptionOperator(const rtExceptionInfo &exception, DumpOperator &excOp);
52 int32_t DumpArgsException(const rtExceptionInfo &exception, const std::string &dumpPath);55 int32_t DumpArgsException(const rtExceptionInfo &exception, const std::string &dumpPath);
53 int32_t DumpArgsExceptionInner(const rtExceptionInfo &exception, const std::string &dumpPath);56 int32_t DumpArgsExceptionInner(const rtExceptionInfo &exception, const std::string &dumpPath);
@@ -74,7 +77,7 @@ private:
74 std::string dumpPath_;77 std::string dumpPath_;
75 std::string extraDumpPath_;78 std::string extraDumpPath_;
76 DumpSetting setting_;79 DumpSetting setting_;
zhangjie
zhangjiezhangjie8月3日

级别:一般 问题:mutex_ 被改为 mutable 以便在 const 方法中加锁,但新增的 IsEnabledExceptionDump()、GetExceptionDumpPath() 和 SaveExceptionInfo() 均未获取 mutex_,而这些方法读取的 coredumpStatus_/exceptionStatus_/argsExceptionStatus_ 以及 dumpPath_ 可能被其他线程并发修改。 影响:在多线程场景下(例如一个线程调用 SaveExceptionInfo,另一个线程调用 ExceptionDumperInit 或 ExceptionModeDowngrade 修改状态),存在数据竞争,可能导致读取到不一致的状态或路径。 修复建议:在 IsEnabledExceptionDump()、GetExceptionDumpPath() 和 SaveExceptionInfo() 中通过 std::lock_guardstd::mutex 保护对共享成员的访问,与 mutex_ 被声明为 mutable 的意图保持一致。

likedislike
yring_8
8月3日 评论:
77- std::mutex mutex_;80+ mutable std::mutex mutex_;
78 std::deque<DumpOperator> agingOperators_;81 std::deque<DumpOperator> agingOperators_;
79 std::map<uint32_t, std::map<uint32_t, std::deque<DumpOperator>>> residentOperators_;82 std::map<uint32_t, std::map<uint32_t, std::deque<DumpOperator>>> residentOperators_;
80 std::vector<ExceptionDumpCallback> callbacks_;83 std::vector<ExceptionDumpCallback> callbacks_;
@@ -210,4 +210,19 @@ std::string DumpDataType::DataTypeToSerialString(const int32_t dataType)
210 return "UNDEFINED";210 return "UNDEFINED";
211 }211 }
212}212}
213+ 
214+std::string DumpDataType::TensorTypeToSerialString(const TensorType tensorType)
215+{
216+ switch (tensorType) {
217+ case TensorType::INPUT:
218+ return "input";
219+ case TensorType::OUTPUT:
220+ return "output";
221+ case TensorType::WORKSPACE:
222+ return "workspace";
223+ default:
224+ IDE_LOGE("TensorTypeToSerialString: tensor type not support %d", static_cast<int32_t>(tensorType));
225+ return "unknown";
226+ }
227+}
213} // namespace Adx228} // namespace Adx
@@ -12,6 +12,7 @@
12#define DUMP_DATATYPE_H12#define DUMP_DATATYPE_H
13#include <cstdint>13#include <cstdint>
14#include <string>14#include <string>
15+#include "adump_pub.h"
15 16 
16namespace Adx {17namespace Adx {
17enum class GeDataType: int32_t {18enum class GeDataType: int32_t {
@@ -123,6 +124,7 @@ public:
123 static int32_t GetIrDataType(GeDataType dataType);124 static int32_t GetIrDataType(GeDataType dataType);
124 static std::string FormatToSerialString(const int32_t format);125 static std::string FormatToSerialString(const int32_t format);
125 static std::string DataTypeToSerialString(const int32_t dataType);126 static std::string DataTypeToSerialString(const int32_t dataType);
127+ static std::string TensorTypeToSerialString(const TensorType tensorType);
126};128};
127} // namespace Adx129} // namespace Adx
128#endif // DUMP_DATATYPE_H130#endif // DUMP_DATATYPE_H
@@ -15,6 +15,7 @@
15#include "dump_printf.h"15#include "dump_printf.h"
16#include "adump_error_manager.h"16#include "adump_error_manager.h"
17#include "str_utils.h"17#include "str_utils.h"
18+#include "common/path.h"
18 19 
19namespace Adx {20namespace Adx {
20uint64_t g_chunk[RING_CHUNK_SIZE + MAX_TENSOR_NUM] = {0};21uint64_t g_chunk[RING_CHUNK_SIZE + MAX_TENSOR_NUM] = {0};
@@ -23,6 +24,100 @@ static std::mutex g_setAssertMtx;
23namespace {24namespace {
24uint32_t g_atomicIndex = 0x2000;25uint32_t g_atomicIndex = 0x2000;
25std::atomic<uint64_t> g_writeIdx{0};26std::atomic<uint64_t> g_writeIdx{0};
27+ 
28+void ConvertAclDumpTensorInner(const acldumpTensorInfo &src, size_t index, TensorInfo &dst)
29+{
30+ dst.type = static_cast<TensorType>(src.type);
31+ dst.tensorSize = src.tensorSize;
32+ dst.format = src.format;
33+ dst.dataType = src.dataType;
34+ dst.tensorAddr = src.tensorAddr;
35+ dst.addrType = static_cast<AddressType>(src.addrType);
36+ dst.placement = static_cast<int32_t>(src.placement);
37+ dst.argsOffSet = static_cast<uint32_t>(index);
38+ 
39+ for (uint32_t i = 0; i < src.shapeNum; ++i) {
40+ dst.shape.emplace_back(static_cast<int64_t>(src.shape[i]));
41+ }
42+ for (uint32_t i = 0; i < src.originShapeNum; ++i) {
43+ dst.originShape.emplace_back(static_cast<int64_t>(src.originShape[i]));
44+ }
45+}
46+ 
47+bool ReportInvalidTensorField(size_t index, const char *field, const std::string &reason)
48+{
49+ std::string param = StrUtils::Format("tensors[%zu].%s", index, field);
50+ REPORT_EP0006_INVALID_ARGUMENT(FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, param,
51+ FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_TENSORS, reason);
52+ return false;
53+}
54+ 
55+bool ReportUnsupportedTensorField(size_t index, const char *field, int32_t value, const char *expected)
56+{
57+ return ReportInvalidTensorField(index, field,
58+ StrUtils::Format(ADUMP_REASON_PARAM_VALUE_NOT_SUPPORTED, std::to_string(value).c_str(), expected));
59+}
60+ 
61+bool CheckAclDumpTensorShape(const acldumpTensorInfo &src, size_t index)
62+{
63+ const std::string maxShapeNum = std::to_string(ACL_DUMP_MAX_SHAPE_NUM);
64+ if (src.shapeNum > ACL_DUMP_MAX_SHAPE_NUM) {
65+ return ReportInvalidTensorField(index, "shapeNum",
66+ StrUtils::Format(ADUMP_REASON_PARAM_VALUE_EXCEED_LIMIT,
67+ std::to_string(src.shapeNum).c_str(), maxShapeNum.c_str()));
68+ }
69+ if (src.originShapeNum > ACL_DUMP_MAX_SHAPE_NUM) {
70+ return ReportInvalidTensorField(index, "originShapeNum",
71+ StrUtils::Format(ADUMP_REASON_PARAM_VALUE_EXCEED_LIMIT,
72+ std::to_string(src.originShapeNum).c_str(), maxShapeNum.c_str()));
73+ }
74+ return true;
75+}
76+ 
77+bool CheckAclDumpTensorEnum(const acldumpTensorInfo &src, size_t index)
78+{
79+ if (src.type != ACL_DUMP_TENSOR_INPUT
80+ && src.type != ACL_DUMP_TENSOR_OUTPUT
81+ && src.type != ACL_DUMP_TENSOR_WORKSPACE) {
82+ return ReportUnsupportedTensorField(index, "type", static_cast<int32_t>(src.type),
83+ "ACL_DUMP_TENSOR_INPUT/ACL_DUMP_TENSOR_OUTPUT/ACL_DUMP_TENSOR_WORKSPACE");
84+ }
85+ if (src.addrType != ACL_DUMP_ADDR_RAW) {
86+ return ReportUnsupportedTensorField(
87+ index, "addrType", static_cast<int32_t>(src.addrType), "ACL_DUMP_ADDR_RAW");
88+ }
89+ if (src.placement != ACL_DUMP_PLACEMENT_DEVICE) {
90+ return ReportUnsupportedTensorField(
91+ index, "placement", static_cast<int32_t>(src.placement), "ACL_DUMP_PLACEMENT_DEVICE");
92+ }
93+ return true;
94+}
95+ 
96+bool CheckAclDumpTensorData(const acldumpTensorInfo &src, size_t index)
97+{
98+ if (src.tensorAddr == nullptr) {
99+ std::string param = StrUtils::Format("tensors[%zu].tensorAddr", index);
100+ REPORT_EP0007_NULL_POINTER(FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, param);
101+ return false;
102+ }
103+ if (src.tensorSize == 0) {
104+ return ReportInvalidTensorField(
105+ index, "tensorSize", StrUtils::Format(ADUMP_REASON_PARAM_MUST_BE_GREATER_THAN, "0"));
106+ }
107+ return true;
108+}
109+ 
110+bool ConvertAclDumpTensor(const acldumpTensorInfo &src, size_t index, TensorInfo &dst)
111+{
112+ if (!CheckAclDumpTensorShape(src, index)
113+ || !CheckAclDumpTensorEnum(src, index)
114+ || !CheckAclDumpTensorData(src, index)) {
115+ return false;
116+ }
117+ 
118+ ConvertAclDumpTensorInner(src, index, dst);
119+ return true;
120+}
26} // namespace121} // namespace
27 122 
28void *AdumpGetSizeInfoAddr(uint32_t space, uint32_t &atomicIndex)123void *AdumpGetSizeInfoAddr(uint32_t space, uint32_t &atomicIndex)
@@ -124,11 +219,119 @@ const char* acldumpGetPath(acldumpType dumpType)
124 case acldumpType::AIC_ERR_BRIEF_DUMP:219 case acldumpType::AIC_ERR_BRIEF_DUMP:
125 case acldumpType::AIC_ERR_NORM_DUMP:220 case acldumpType::AIC_ERR_NORM_DUMP:
126 case acldumpType::AIC_ERR_DETAIL_DUMP:221 case acldumpType::AIC_ERR_DETAIL_DUMP:
127- return Adx::DumpManager::Instance().GetExceptionDumpPath();222+ return Adx::DumpManager::Instance().GetExtraExceptionDumpPath();
128 case acldumpType::DATA_DUMP:223 case acldumpType::DATA_DUMP:
129 case acldumpType::OVERFLOW_DUMP:224 case acldumpType::OVERFLOW_DUMP:
130 return Adx::DumpManager::Instance().GetDataDumpPath();225 return Adx::DumpManager::Instance().GetDataDumpPath();
131 default:226 default:
132 return nullptr;227 return nullptr;
133 }228 }
134-}229+}
230+ 
231+/**
232+ * @ingroup AscendCL
233+ * @brief Save custom exception info (tensors) to the Exception Dump path.
234+ * @retval ACL_SUCCESS The function is successfully executed.
235+ * @retval OtherValues Failure
236+ */
237+aclError acldumpSaveExceptionInfo(const char *fileName, const char *userTag,
238+ const acldumpTensorInfo *tensors, size_t tensorCount)
239+{
240+ if (fileName == nullptr) {
241+ REPORT_EP0007_NULL_POINTER(
242+ Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, Adx::FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_FILENAME);
243+ return ACL_ERROR_INVALID_PARAM;
244+ }
245+ 
246+ if (fileName[0] == '\0') {
247+ REPORT_EP0006_INVALID_ARGUMENT(Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, "",
248+ Adx::FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_FILENAME, Adx::ADUMP_REASON_PARAM_PATH_EMPTY);
249+ return ACL_ERROR_INVALID_PARAM;
250+ }
251+ 
252+ if (Adx::Path::HasParentDirSegment(fileName)) {
253+ REPORT_EP0006_INVALID_ARGUMENT(Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, fileName,
254+ Adx::FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_FILENAME, Adx::ADUMP_REASON_PARAM_PATH_HAS_PARENT_DIR);
255+ return ACL_ERROR_INVALID_PARAM;
256+ }
257+ 
258+ if (tensors == nullptr) {
259+ REPORT_EP0007_NULL_POINTER(
260+ Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, Adx::FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_TENSORS);
261+ return ACL_ERROR_INVALID_PARAM;
262+ }
263+ 
264+ if (tensorCount == 0) {
265+ const std::string reason = Adx::StrUtils::Format(Adx::ADUMP_REASON_PARAM_MUST_BE_GREATER_THAN, "0");
266+ REPORT_EP0006_INVALID_ARGUMENT(Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, std::to_string(tensorCount),
267+ Adx::FUNC_ACL_DUMP_SAVE_EXCEPTION_INFO_PARAM_TENSORCOUNT, reason);
268+ return ACL_ERROR_INVALID_PARAM;
269+ }
270+ 
271+ if (!Adx::DumpManager::Instance().IsEnabledExceptionDump()) {
272+ const std::string reason = Adx::StrUtils::Format(
273+ Adx::ADUMP_REASON_EXCEPTION_DUMP_NOT_ENABLED, Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO);
274+ REPORT_EP0008_API_CALL_SEQUENCE(Adx::FUNC_NAME_ACL_DUMP_SAVE_EXCEPTION_INFO, reason);
275+ return ACL_ERROR_FAILURE;
276+ }
277+ 
278+ std::vector<Adx::TensorInfo> tensorInfos(tensorCount);
J
Jjinyingqi8月3日

问题:acldumpSaveExceptionInfo 未限制 tensorCount,上来就按用户传入值构造 vector。

  • 严重程度:major
  • 影响:调用方传入极大的 tensorCount 时可能触发超大内存分配、std::bad_alloc 导致进程异常终止,随后循环还会按该数量读取 tensors,存在越界读取风险。
  • 修改建议:在分配前校验 tensorCount 上限,建议复用异常 dump 已有的 EXCEPTION_DUMP_MAX_TENSOR_NUM 约束,超限直接结构化上报并返回 ACL_ERROR_INVALID_PARAM。
likedislike
yring_8
8月3日 评论:
279+ for (size_t i = 0; i < tensorCount; ++i) {
280+ if (!Adx::ConvertAclDumpTensor(tensors[i], i, tensorInfos[i])) {
281+ return ACL_ERROR_INVALID_PARAM;
282+ }
283+ }
284+ 
285+ const std::string userTagStr = (userTag == nullptr) ? "" : userTag;
286+ const int32_t ret = Adx::DumpManager::Instance().SaveExceptionInfo(fileName, userTagStr, tensorInfos);
287+ return ret == 0 ? ACL_SUCCESS : ACL_ERROR_FAILURE;
288+}
289+ 
290+/**
291+ * @ingroup AscendCL
292+ * @brief Get the Exception Dump root path({dump_path}/extra-info/data-dump/{deviceId}/).
293+ * @retval ACL_SUCCESS The function is successfully executed.
294+ * @retval OtherValues Failure
295+ */
296+aclError acldumpGetExceptionInfoPath(char *path, size_t maxLen)
297+{
298+ if (path == nullptr) {
299+ REPORT_EP0007_NULL_POINTER(
300+ Adx::FUNC_NAME_ACL_DUMP_GET_EXCEPTION_INFO_PATH, Adx::FUNC_ACL_DUMP_GET_EXCEPTION_INFO_PATH_PARAM_PATH);
301+ return ACL_ERROR_INVALID_PARAM;
302+ }
303+ if (maxLen <= 1) {
304+ std::string reason = Adx::StrUtils::Format(Adx::ADUMP_REASON_PARAM_MUST_BE_GREATER_THAN, "1");
305+ REPORT_EP0006_INVALID_ARGUMENT(Adx::FUNC_NAME_ACL_DUMP_GET_EXCEPTION_INFO_PATH, std::to_string(maxLen),
306+ Adx::FUNC_ACL_DUMP_GET_EXCEPTION_INFO_PATH_PARAM_MAXLEN, reason);
307+ return ACL_ERROR_INVALID_PARAM;
308+ }
309+ 
310+ if (!Adx::DumpManager::Instance().IsEnabledExceptionDump()) {
311+ const std::string reason = Adx::StrUtils::Format(
312+ Adx::ADUMP_REASON_EXCEPTION_DUMP_NOT_ENABLED, Adx::FUNC_NAME_ACL_DUMP_GET_EXCEPTION_INFO_PATH);
313+ REPORT_EP0008_API_CALL_SEQUENCE(Adx::FUNC_NAME_ACL_DUMP_GET_EXCEPTION_INFO_PATH, reason);
314+ return ACL_ERROR_FAILURE;
315+ }
316+ 
317+ std::string dumpPath;
318+ int32_t ret = Adx::DumpManager::Instance().GetExceptionDumpPath(dumpPath);
319+ if (ret != 0 || dumpPath.empty()) {
320+ IDE_LOGE("Get the exception dump path failed, path size=%zu, maxLen=%zu.", dumpPath.size(), maxLen);
321+ return ACL_ERROR_FAILURE;
322+ }
323+ 
324+ if (dumpPath.size() + 1 > maxLen) {
325+ std::string reason = Adx::StrUtils::Format(Adx::ADUMP_REASON_BUFFER_SIZE_NOT_ENOUGH,
326+ std::to_string(maxLen).c_str(), std::to_string(dumpPath.size() + 1).c_str());
327+ REPORT_EP0006_INVALID_ARGUMENT(Adx::FUNC_NAME_ACL_DUMP_GET_EXCEPTION_INFO_PATH, std::to_string(maxLen),
328+ Adx::FUNC_ACL_DUMP_GET_EXCEPTION_INFO_PATH_PARAM_MAXLEN, reason);
329+ return ACL_ERROR_INVALID_PARAM;
330+ }
331+ if (strcpy_s(path, maxLen, dumpPath.c_str()) != EOK) {
332+ IDE_LOGE("Copy the path to buffer failed when get the exception dump path, path size=%zu, maxLen=%zu.",
333+ dumpPath.size(), maxLen);
334+ return ACL_ERROR_FAILURE;
335+ }
336+ return ACL_SUCCESS;
337+}
@@ -34,6 +34,9 @@
34#include "kernel_dfx_dumper.h"34#include "kernel_dfx_dumper.h"
35#include "adx_dump_record.h"35#include "adx_dump_record.h"
36#include "common/file.h"36#include "common/file.h"
37+#include "common/path.h"
38+#include "sys_utils.h"
39+#include "dump_file.h"
37#include "adx_datadump_server.h"40#include "adx_datadump_server.h"
38 41 
39namespace Adx {42namespace Adx {
@@ -683,6 +686,12 @@ void DumpManager::ExceptionModeDowngrade()
683 exceptionDumper_.ExceptionModeDowngrade();686 exceptionDumper_.ExceptionModeDowngrade();
684}687}
685 688 
689+bool DumpManager::IsEnabledExceptionDump()
690+{
zhangjie
zhangjiezhangjie8月3日

级别:提示 问题:DumpManager::IsEnabledExceptionDump() 未获取 resourceMtx_ 锁即调用 exceptionDumper_.IsEnabledExceptionDump(),而 GetExtraExceptionDumpPath 等方法在同一锁下操作 exceptionDumper_。 影响:与 ExceptionDumper 层面的线程安全问题叠加,锁策略不一致增加维护和理解成本。 修复建议:评估是否需要在 DumpManager 层面加锁,或统一在 ExceptionDumper 层面使用 mutex_ 保护所有公共方法。

likedislike
yring_8
8月3日 评论:
691+ std::lock_guard<std::mutex> lk(resourceMtx_);
692+ return exceptionDumper_.IsEnabledExceptionDump();
693+}
694+ 
686int32_t DumpManager::RegisterCallback(uint32_t moduleId, AdumpCallback enableFunc, AdumpCallback disableFunc)695int32_t DumpManager::RegisterCallback(uint32_t moduleId, AdumpCallback enableFunc, AdumpCallback disableFunc)
687{696{
688 if (enableFunc == nullptr) {697 if (enableFunc == nullptr) {
@@ -772,7 +781,7 @@ int32_t DumpManager::StopDumpArgs()
772 return 0;781 return 0;
773}782}
774 783 
775-const char* DumpManager::GetExceptionDumpPath()784+const char* DumpManager::GetExtraExceptionDumpPath()
776{785{
777 std::lock_guard<std::mutex> lk(resourceMtx_);786 std::lock_guard<std::mutex> lk(resourceMtx_);
778 exceptionDumper_.CreateExtraDumpPath();787 exceptionDumper_.CreateExtraDumpPath();
@@ -785,22 +794,26 @@ const char* DumpManager::GetDataDumpPath()
785 return dumpSetting_.GetDumpCPath();794 return dumpSetting_.GetDumpCPath();
786}795}
787 796 
797+int32_t DumpManager::GetExceptionDumpPath(std::string &path)
798+{
799+ std::lock_guard<std::mutex> lk(resourceMtx_);
800+ return exceptionDumper_.GetExceptionDumpPath(path);
801+}
802+ 
803+int32_t DumpManager::SaveExceptionInfo(const std::string& fileName, const std::string& userTag,
804+ const std::vector<TensorInfo>& tensors)
805+{
806+ std::lock_guard<std::mutex> lk(resourceMtx_);
807+ return exceptionDumper_.SaveExceptionInfo(fileName, userTag, tensors);
808+}
809+ 
788int32_t DumpManager::SaveFile(const char* data, size_t dataLen, const char* fileName, SaveType type)810int32_t DumpManager::SaveFile(const char* data, size_t dataLen, const char* fileName, SaveType type)
789{811{
790- Adx::Path filePath(opInfoRecordPath_);812+ std::string canonicalPath;
791- filePath.Concat(fileName);813+ if (!Adx::Path::BuildFullPathUnderRoot(opInfoRecordPath_, fileName, canonicalPath)) {
792- Adx::Path dirPath = filePath.ParentPath();814+ IDE_LOGE("invalid fileName[%s], may escape root path.", fileName);
793- if (!dirPath.Exist()) {815+ return -1;
794- if (!dirPath.CreateDirectory(true)) {
795- IDE_LOGE("create directory[%s] failed", dirPath.GetCString());
796- return -1;
797- }
798 }816 }
799- if (!dirPath.RealPath()) {
800- IDE_LOGE("get real path failed, path:%s", dirPath.GetCString());
801- }
802- 
803- std::string canonicalPath = dirPath.GetString() + "/" + filePath.GetFileName();
804 int32_t openFlag = 0;817 int32_t openFlag = 0;
805 if (type == SaveType::OVERWRITE) {818 if (type == SaveType::OVERWRITE) {
806 openFlag = O_CREAT | O_WRONLY | O_TRUNC;819 openFlag = O_CREAT | O_WRONLY | O_TRUNC;
@@ -50,10 +50,13 @@ public:
50 DumpSetting GetDumpSetting() const;50 DumpSetting GetDumpSetting() const;
51 void KFCResourceInit();51 void KFCResourceInit();
52 void ExceptionModeDowngrade();52 void ExceptionModeDowngrade();
53+ bool IsEnabledExceptionDump();
53 int32_t RegisterCallback(uint32_t moduleId, AdumpCallback enableFunc, AdumpCallback disableFunc);54 int32_t RegisterCallback(uint32_t moduleId, AdumpCallback enableFunc, AdumpCallback disableFunc);
54 int32_t StartDumpArgs(const std::string& dumpPath);55 int32_t StartDumpArgs(const std::string& dumpPath);
55 int32_t StopDumpArgs();56 int32_t StopDumpArgs();
56 int32_t SaveFile(const char* data, size_t dataLen, const char* fileName, SaveType type);57 int32_t SaveFile(const char* data, size_t dataLen, const char* fileName, SaveType type);
58+ int32_t SaveExceptionInfo(const std::string& fileName, const std::string& userTag,
59+ const std::vector<TensorInfo>& tensors);
57 int32_t DumpOperatorV2(60 int32_t DumpOperatorV2(
58 const std::string& opType, const std::string& opName, const std::vector<TensorInfoV2>& tensors,61 const std::string& opType, const std::string& opName, const std::vector<TensorInfoV2>& tensors,
59 rtStream_t stream);62 rtStream_t stream);
@@ -62,7 +65,8 @@ public:
62 void AddExceptionOpV2(const OperatorInfoV2& opInfo);65 void AddExceptionOpV2(const OperatorInfoV2& opInfo);
63 void ConvertOperatorInfo(const OperatorInfo& opInfo, OperatorInfoV2& operatorInfoV2) const;66 void ConvertOperatorInfo(const OperatorInfo& opInfo, OperatorInfoV2& operatorInfoV2) const;
64 std::vector<TensorInfoV2> ConvertTensorInfoToDumpTensorV2(const std::vector<TensorInfo>& tensorInfos) const;67 std::vector<TensorInfoV2> ConvertTensorInfoToDumpTensorV2(const std::vector<TensorInfo>& tensorInfos) const;
65- const char* GetExceptionDumpPath();68+ const char* GetExtraExceptionDumpPath();
69+ int32_t GetExceptionDumpPath(std::string &path);
66 const char* GetDataDumpPath();70 const char* GetDataDumpPath();
67 bool StartDataDumpServer();71 bool StartDataDumpServer();
68 bool StopDataDumpServer();72 bool StopDataDumpServer();
@@ -8,6 +8,7 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10#include <gtest/gtest.h>10#include <gtest/gtest.h>
11+#include <unistd.h>
11#include "mockcpp/mockcpp.hpp"12#include "mockcpp/mockcpp.hpp"
12#include "case_workspace.h"13#include "case_workspace.h"
13#include "adump_pub.h"14#include "adump_pub.h"
@@ -123,4 +124,73 @@ TEST_F(CommonPathUtest, Test_Path_With_Entity)
123 EXPECT_EQ(Path(recursionCreateDir).CreateDirectory(), false);124 EXPECT_EQ(Path(recursionCreateDir).CreateDirectory(), false);
124 EXPECT_EQ(Path(recursionCreateDir).CreateDirectory(true), true);125 EXPECT_EQ(Path(recursionCreateDir).CreateDirectory(true), true);
125 EXPECT_EQ(Path(recursionCreateDir).IsDirectory(), true);126 EXPECT_EQ(Path(recursionCreateDir).IsDirectory(), true);
126-}127+}
128+ 
129+TEST_F(CommonPathUtest, Test_Path_HasParentDirSegment)
130+{
131+ EXPECT_EQ(Path::HasParentDirSegment(".."), true);
132+ EXPECT_EQ(Path::HasParentDirSegment("../file.bin"), true);
133+ EXPECT_EQ(Path::HasParentDirSegment("dir/../file.bin"), true);
134+ EXPECT_EQ(Path::HasParentDirSegment("dir/.."), true);
135+ 
136+ EXPECT_EQ(Path::HasParentDirSegment("file.bin"), false);
137+ EXPECT_EQ(Path::HasParentDirSegment("my..file.bin"), false);
138+ EXPECT_EQ(Path::HasParentDirSegment("dir/..file.bin"), false);
139+ EXPECT_EQ(Path::HasParentDirSegment(".../file.bin"), false);
140+}
141+ 
142+TEST_F(CommonPathUtest, Test_Path_IsUnderDirectory)
143+{
144+ EXPECT_EQ(Path::IsUnderDirectory("/root", "/root"), true);
145+ EXPECT_EQ(Path::IsUnderDirectory("/root", "/root/"), true);
146+ EXPECT_EQ(Path::IsUnderDirectory("/root/", "/root/sub"), true);
147+ EXPECT_EQ(Path::IsUnderDirectory("/root", "/root/sub/deep"), true);
148+ 
149+ // 前缀相同但不是同一路径段,不能误判为子路径
150+ EXPECT_EQ(Path::IsUnderDirectory("/root", "/root_evil"), false);
151+ EXPECT_EQ(Path::IsUnderDirectory("/root", "/rootevil/sub"), false);
152+ EXPECT_EQ(Path::IsUnderDirectory("/root/sub", "/root"), false);
153+ EXPECT_EQ(Path::IsUnderDirectory("/root", "/other"), false);
154+ 
155+ EXPECT_EQ(Path::IsUnderDirectory("", "/root"), false);
156+ EXPECT_EQ(Path::IsUnderDirectory("/root", ""), false);
157+}
158+ 
159+TEST_F(CommonPathUtest, Test_Path_BuildFullPathUnderRoot)
160+{
161+ Tools::CaseWorkspace ws("Test_Path_BuildFullPathUnderRoot");
162+ std::string root = ws.Mkdir("dump_root");
163+ std::string canonicalFile;
164+ 
165+ EXPECT_EQ(Path::BuildFullPathUnderRoot("", "file.bin", canonicalFile), false);
166+ EXPECT_EQ(Path::BuildFullPathUnderRoot(root, "", canonicalFile), false);
167+ EXPECT_EQ(Path::BuildFullPathUnderRoot(root, "../escape.bin", canonicalFile), false);
168+ 
169+ // 正常场景:文件落在根目录下,父目录被自动创建
170+ EXPECT_EQ(Path::BuildFullPathUnderRoot(root, "file.bin", canonicalFile), true);
171+ EXPECT_EQ(canonicalFile, Path(root).Concat("file.bin").GetString());
172+ 
173+ EXPECT_EQ(Path::BuildFullPathUnderRoot(root, "sub/dir/file.bin", canonicalFile), true);
174+ EXPECT_EQ(Path::IsUnderDirectory(root, canonicalFile), true);
175+ EXPECT_EQ(Path(root).Concat("sub/dir").GetString(), Path(canonicalFile).ParentPath().GetString());
176+ 
177+ // 根目录不存在时会被递归创建,仍视为合法
178+ std::string newRoot = ws.Root() + "/no_exist_root";
179+ EXPECT_EQ(Path::BuildFullPathUnderRoot(newRoot, "file.bin", canonicalFile), true);
180+ EXPECT_EQ(Path::IsUnderDirectory(newRoot, canonicalFile), true);
181+}
182+ 
183+TEST_F(CommonPathUtest, Test_Path_BuildFullPathUnderRoot_RejectSymlinkEscape)
184+{
185+ Tools::CaseWorkspace ws("Test_Path_BuildFullPathUnderRoot_Symlink");
186+ std::string root = ws.Mkdir("dump_root");
187+ std::string outside = ws.Mkdir("outside_dir");
188+ std::string canonicalFile;
189+ 
190+ // 在落盘根目录下预置一个指向外部的软链接目录
191+ std::string linkPath = Path(root).Concat("escape_link").GetString();
192+ ASSERT_EQ(symlink(outside.c_str(), linkPath.c_str()), 0);
193+ 
194+ // relativeFile 不含 '..',但经软链接解析后逃逸出 rootPath,必须被拒绝
195+ EXPECT_EQ(Path::BuildFullPathUnderRoot(root, "escape_link/file.bin", canonicalFile), false);
196+}
@@ -98,6 +98,49 @@ TEST_F(DumpFileUtest, Test_DumpData)
98 EXPECT_EQ(checker.Load(dumpFilePath), false);98 EXPECT_EQ(checker.Load(dumpFilePath), false);
99}99}
100 100 
101+TEST_F(DumpFileUtest, Test_SetOpAttr)
102+{
103+ Tools::CaseWorkspace ws("Test_SetOpAttr");
104+ std::string dumpFilePath = ws.Root() + "/dump_file_attr.bin";
105+ 
106+ // 构造一个真实 host 数据的 input tensor,保证有数据落盘
107+ int64_t hostData = 12345;
108+ TensorInfoV2 tensorV2 = {};
109+ tensorV2.addrType = AddressType::TRADITIONAL;
110+ tensorV2.type = TensorType::INPUT;
111+ tensorV2.dataType = static_cast<int32_t>(GeDataType::DT_INT64);
112+ tensorV2.argsOffSet = 0;
113+ tensorV2.format = 2; // ND
114+ tensorV2.shape = {1};
115+ tensorV2.originShape = {1};
116+ tensorV2.tensorAddr = &hostData;
117+ tensorV2.tensorSize = sizeof(hostData);
118+ tensorV2.placement = TensorPlacement::kOnDeviceHbm;
119+ 
120+ std::vector<DumpTensor> inputTensors;
121+ inputTensors.emplace_back(tensorV2);
122+ 
123+ // 屏蔽真实 device 内存拷贝,直接写 host 数据
124+ // 堆分配:CopyDeviceToHost 返回值由 HOST_RT_MEMORY_GUARD 释放,FreeHost 打桩防止 double-free
125+ void *fakeHostData = malloc(sizeof(hostData));
126+ ASSERT_NE(fakeHostData, nullptr);
127+ MOCKER(rtMemGetInfoByType).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
128+ MOCKER(&DumpMemory::CopyDeviceToHost).stubs().will(returnValue(fakeHostData));
129+ MOCKER(&DumpMemory::FreeHost).stubs();
130+ 
131+ DumpFile dumpFile(0, dumpFilePath);
132+ dumpFile.SetHeader("attr_op");
133+ dumpFile.SetOpAttr("user_tag", "component=demo;stage=forward");
134+ dumpFile.SetInputTensors(inputTensors);
135+ 
136+ std::vector<std::string> logRecord;
137+ int32_t ret = dumpFile.Dump(logRecord);
138+ EXPECT_EQ(ret, ADUMP_SUCCESS);
139+ 
140+ DumpFileChecker checker;
141+ EXPECT_EQ(checker.Load(dumpFilePath), true);
142+}
143+ 
101// TEST_F(DumpFileUtest, Test_Dump_With_CopyDeviceData_Fail)144// TEST_F(DumpFileUtest, Test_Dump_With_CopyDeviceData_Fail)
102// {145// {
103// Tools::CaseWorkspace ws("Test_Dump_With_CopyDeviceData_Fail");146// Tools::CaseWorkspace ws("Test_Dump_With_CopyDeviceData_Fail");
@@ -21,6 +21,7 @@
21#include "sys_utils.h"21#include "sys_utils.h"
22#include "dump_manager.h"22#include "dump_manager.h"
23#include "operator_dumper.h"23#include "operator_dumper.h"
24+#include "dump_file.h"
24#include "acl/acl_base.h"25#include "acl/acl_base.h"
25#include "acl/acl_dump.h"26#include "acl/acl_dump.h"
26#include "sys_utils.h"27#include "sys_utils.h"
@@ -839,6 +840,281 @@ TEST_F(AdumpApiUtest, Test_acldumpGetPath)
839 EXPECT_EQ(path, DumpManager::Instance().dumpSetting_.dumpPath_.path_.c_str());840 EXPECT_EQ(path, DumpManager::Instance().dumpSetting_.dumpPath_.path_.c_str());
840}841}
841 842 
843+namespace {
844+acldumpTensorInfo MakeAclDumpTensor(acldumpTensorType type, int64_t *addr, size_t size)
845+{
846+ acldumpTensorInfo tensor{};
847+ tensor.type = type;
848+ tensor.tensorSize = size;
849+ tensor.format = 2; // ND
850+ tensor.dataType = 0; // DT_UNDEFINED
851+ tensor.tensorAddr = addr;
852+ tensor.addrType = ACL_DUMP_ADDR_RAW;
853+ tensor.placement = ACL_DUMP_PLACEMENT_DEVICE;
854+ tensor.argsOffset = 0;
855+ tensor.shapeNum = 2;
856+ tensor.shape[0] = 4;
857+ tensor.shape[1] = 2;
858+ tensor.originShapeNum = 2;
859+ tensor.originShape[0] = 4;
860+ tensor.originShape[1] = 2;
861+ return tensor;
862+}
863+}
864+ 
865+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_NullFileName)
866+{
867+ int64_t data = 0;
868+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
869+ EXPECT_EQ(acldumpSaveExceptionInfo(nullptr, "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
870+}
871+ 
872+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_EmptyFileName)
873+{
874+ int64_t data = 0;
875+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
876+ EXPECT_EQ(acldumpSaveExceptionInfo("", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
877+}
878+ 
879+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_FileNameHasParentDir)
880+{
881+ int64_t data = 0;
882+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
883+ // fileName 含 '..' 路径段应在入口被拦截,返回 ACL_ERROR_INVALID_PARAM
884+ EXPECT_EQ(acldumpSaveExceptionInfo("../evil.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
885+ EXPECT_EQ(acldumpSaveExceptionInfo("sub/../../x.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
886+}
887+ 
888+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_NullTensorsWithCount)
889+{
890+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", nullptr, 1), ACL_ERROR_INVALID_PARAM);
891+}
892+ 
893+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_PathNotReady)
894+{
895+ // CreateExtraDumpPath fails -> empty root path -> failure
896+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
897+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(false));
898+ int64_t data = 0;
899+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
900+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_FAILURE);
901+}
902+ 
903+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_Success)
904+{
905+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
906+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(true));
907+ MOCKER_CPP(&Path::RealPath).stubs().will(returnValue(true));
908+ MOCKER_CPP(&Path::IsDirectory).stubs().will(returnValue(true));
909+ MOCKER_CPP(&Path::Exist).stubs().will(returnValue(true));
910+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
911+ MOCKER(&DumpFile::Dump).stubs().will(returnValue(ADUMP_SUCCESS));
912+ MOCKER(mmChmod).stubs().will(returnValue(0));
913+ 
914+ int64_t inData = 0;
915+ int64_t outData = 0;
916+ int64_t wsData = 0;
917+ std::vector<acldumpTensorInfo> tensors = {
918+ MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &inData, sizeof(inData)),
919+ MakeAclDumpTensor(ACL_DUMP_TENSOR_OUTPUT, &outData, sizeof(outData)),
920+ MakeAclDumpTensor(ACL_DUMP_TENSOR_WORKSPACE, &wsData, sizeof(wsData)),
921+ };
922+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "component=demo", tensors.data(), tensors.size()), ACL_SUCCESS);
923+}
924+ 
925+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_NullUserTag)
926+{
927+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
928+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(true));
929+ MOCKER_CPP(&Path::RealPath).stubs().will(returnValue(true));
930+ MOCKER_CPP(&Path::IsDirectory).stubs().will(returnValue(true));
931+ MOCKER_CPP(&Path::Exist).stubs().will(returnValue(true));
932+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
933+ MOCKER(&DumpFile::Dump).stubs().will(returnValue(ADUMP_SUCCESS));
934+ MOCKER(mmChmod).stubs().will(returnValue(0));
935+ 
936+ int64_t data = 0;
937+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
938+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", nullptr, &tensor, 1), ACL_SUCCESS);
939+}
940+ 
941+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_FileNameHasTimestampSuffix)
942+{
943+ // 落盘前应查询毫秒时间戳并追加到文件名,避免重复运行覆盖已有文件或被已有文件阻塞落盘。
944+ // GetCurrentTimeWithMillisecond 被调用即证明时间戳后缀逻辑生效。
945+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
946+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(true));
947+ MOCKER_CPP(&Path::RealPath).stubs().will(returnValue(true));
948+ MOCKER_CPP(&Path::IsDirectory).stubs().will(returnValue(true));
949+ MOCKER_CPP(&Path::Exist).stubs().will(returnValue(true));
950+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
951+ MOCKER_CPP(&SysUtils::GetCurrentTimeWithMillisecond)
952+ .expects(once())
953+ .will(returnValue(std::string("20260721153012345")));
954+ MOCKER(&DumpFile::Dump).stubs().will(returnValue(ADUMP_SUCCESS));
955+ MOCKER(mmChmod).stubs().will(returnValue(0));
956+ 
957+ int64_t data = 0;
958+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
959+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_SUCCESS);
960+}
961+ 
962+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_ShapeNumOverMax)
963+{
964+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
965+ int64_t data = 0;
966+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
967+ tensor.shapeNum = ACL_DUMP_MAX_SHAPE_NUM + 1;
968+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
969+}
970+ 
971+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_OriginShapeNumOverMax)
972+{
973+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
974+ int64_t data = 0;
975+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
976+ tensor.originShapeNum = ACL_DUMP_MAX_SHAPE_NUM + 1;
977+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
978+}
979+ 
980+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_UnsupportedTensorType)
981+{
982+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
983+ int64_t data = 0;
984+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
985+ // out-of-range value is rejected as well
986+ tensor.type = static_cast<acldumpTensorType>(ACL_DUMP_TENSOR_WORKSPACE + 1);
987+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
988+}
989+ 
990+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_UnsupportedAddrType)
991+{
992+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
993+ int64_t data = 0;
994+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
995+ tensor.addrType = ACL_DUMP_ADDR_PTR;
996+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
997+ tensor.addrType = ACL_DUMP_ADDR_PTR_PTR;
998+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
999+ // out-of-range value is rejected as well
1000+ tensor.addrType = static_cast<acldumpTensorAddressType>(ACL_DUMP_ADDR_RAW + 1);
1001+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
1002+}
1003+ 
1004+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_UnsupportedPlacement)
1005+{
1006+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
1007+ int64_t data = 0;
1008+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
1009+ tensor.placement = ACL_DUMP_PLACEMENT_HOST;
1010+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
1011+ tensor.placement = ACL_DUMP_PLACEMENT_END;
1012+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
1013+}
1014+ 
1015+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_ZeroTensorCount)
1016+{
1017+ // tensorCount 为 0 时无数据可落盘,必须在入口拦截,不能报成功
1018+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
1019+ int64_t data = 0;
1020+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
1021+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 0), ACL_ERROR_INVALID_PARAM);
1022+}
1023+ 
1024+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_NullTensorAddr)
1025+{
1026+ // tensorAddr 为空的 tensor 会在组装 dump 数据时被跳过,必须在入口拦截,不能报成功
1027+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
1028+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, nullptr, sizeof(int64_t));
1029+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
1030+}
1031+ 
1032+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_ZeroTensorSize)
1033+{
1034+ // tensorSize 为 0 的 tensor 同样会被跳过,必须在入口拦截,不能报成功
1035+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
1036+ int64_t data = 0;
1037+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, 0);
1038+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_INVALID_PARAM);
1039+}
1040+ 
1041+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_InvalidTensorInMiddleRejected)
1042+{
1043+ // 数组中任意一个非法 tensor 都应导致整体失败,不能只落盘合法的部分
1044+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
1045+ int64_t inData = 0;
1046+ int64_t outData = 0;
1047+ std::vector<acldumpTensorInfo> tensors = {
1048+ MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &inData, sizeof(inData)),
1049+ MakeAclDumpTensor(ACL_DUMP_TENSOR_OUTPUT, nullptr, sizeof(outData)),
1050+ };
1051+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", tensors.data(), tensors.size()), ACL_ERROR_INVALID_PARAM);
1052+}
1053+ 
1054+TEST_F(AdumpApiUtest, Test_acldumpSaveExceptionInfo_DumpFail)
1055+{
1056+ MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true));
1057+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(true));
1058+ MOCKER_CPP(&Path::RealPath).stubs().will(returnValue(true));
1059+ MOCKER_CPP(&Path::IsDirectory).stubs().will(returnValue(true));
1060+ MOCKER_CPP(&Path::Exist).stubs().will(returnValue(true));
1061+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
1062+ MOCKER(&DumpFile::Dump).stubs().will(returnValue(ADUMP_FAILED));
1063+ 
1064+ int64_t data = 0;
1065+ acldumpTensorInfo tensor = MakeAclDumpTensor(ACL_DUMP_TENSOR_INPUT, &data, sizeof(data));
1066+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_FAILURE);
1067+}
1068+ 
1069+TEST_F(AdumpApiUtest, Test_acldumpGetExceptionInfoPath_InvalidParam)
1070+{
1071+ char buf[64] = {0};
1072+ EXPECT_EQ(acldumpGetExceptionInfoPath(nullptr, sizeof(buf)), ACL_ERROR_INVALID_PARAM);
1073+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, 0), ACL_ERROR_INVALID_PARAM);
1074+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, 1), ACL_ERROR_INVALID_PARAM);
1075+}
zhangjie
zhangjiezhangjie8月3日

级别:一般 问题:Test_acldumpSaveExceptionInfo_DumpFail 未 mock IsEnabledExceptionDump 返回 true,因此函数在异常 Dump 未使能检查处即返回 ACL_ERROR_FAILURE,实际并未走到 DumpFile::Dump 的失败分支。 影响:测试名为 DumpFail 但实际验证的是 not-enabled 路径,Dump 失败路径未被真正覆盖,存在测试缺口。 修复建议:在该测试中补充 MOCKER_CPP(&ExceptionDumper::IsEnabledExceptionDump).stubs().will(returnValue(true)) 及必要的 Path mock,使执行流真正到达 Dump 调用并验证其返回 ADUMP_FAILED 时的行为。

likedislike
yring_8
8月6日 评论:
1076+ 
1077+TEST_F(AdumpApiUtest, Test_acldumpGetExceptionInfoPath_PathNotReady)
1078+{
1079+ // 已使能但 CreateDeviceDumpPath 失败 -> empty path -> failure
1080+ DumpManager::Instance().exceptionDumper_.argsExceptionStatus_ = true;
1081+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(false));
1082+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
1083+ char buf[64] = {0};
1084+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, sizeof(buf)), ACL_ERROR_FAILURE);
1085+}
1086+ 
1087+TEST_F(AdumpApiUtest, Test_acldumpGetExceptionInfoPath_NotEnabled)
1088+{
1089+ // exception dump 未使能 -> 返回空 -> 失败
1090+ DumpManager::Instance().exceptionDumper_.argsExceptionStatus_ = false;
1091+ DumpManager::Instance().exceptionDumper_.exceptionStatus_ = false;
1092+ DumpManager::Instance().exceptionDumper_.coredumpStatus_ = false;
1093+ char buf[4096] = {0};
1094+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, sizeof(buf)), ACL_ERROR_FAILURE);
1095+}
1096+ 
1097+TEST_F(AdumpApiUtest, Test_acldumpGetExceptionInfoPath_Success)
1098+{
1099+ DumpManager::Instance().exceptionDumper_.argsExceptionStatus_ = true;
1100+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(true));
1101+ MOCKER_CPP(&Path::RealPath).stubs().will(returnValue(true));
1102+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
1103+ char buf[4096] = {0};
1104+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, sizeof(buf)), ACL_SUCCESS);
1105+ EXPECT_GT(strlen(buf), 0U);
1106+}
1107+ 
1108+TEST_F(AdumpApiUtest, Test_acldumpGetExceptionInfoPath_BufferTooSmall)
1109+{
1110+ DumpManager::Instance().exceptionDumper_.argsExceptionStatus_ = true;
1111+ MOCKER_CPP(&Path::CreateDirectory).stubs().will(returnValue(true));
1112+ MOCKER_CPP(&Path::RealPath).stubs().will(returnValue(true));
1113+ MOCKER(rtGetDevice).stubs().will(returnValue((rtError_t)RT_ERROR_NONE));
1114+ char buf[2] = {0};
1115+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, sizeof(buf)), ACL_ERROR_INVALID_PARAM);
1116+}
1117+ 
842TEST_F(AdumpApiUtest, Test_AdumpRegExceptionDumpCallback_Null)1118TEST_F(AdumpApiUtest, Test_AdumpRegExceptionDumpCallback_Null)
843{1119{
844 int32_t ret = AdumpRegExceptionDumpCallback(nullptr);1120 int32_t ret = AdumpRegExceptionDumpCallback(nullptr);
@@ -66,3 +66,24 @@ TEST_F(TinyAdumpApiPlatformUtest, Test_acldumpGetPath)
66{66{
67 EXPECT_EQ(acldumpGetPath(DATA_DUMP), nullptr);67 EXPECT_EQ(acldumpGetPath(DATA_DUMP), nullptr);
68}68}
69+ 
70+TEST_F(TinyAdumpApiPlatformUtest, Test_acldumpSaveExceptionInfo_NotSupport)
71+{
72+ int64_t data = 0;
73+ acldumpTensorInfo tensor{};
74+ tensor.type = ACL_DUMP_TENSOR_INPUT;
75+ tensor.tensorSize = sizeof(data);
76+ tensor.tensorAddr = &data;
77+ tensor.shapeNum = 1;
78+ tensor.shape[0] = 1;
79+ EXPECT_EQ(acldumpSaveExceptionInfo("exc.bin", "tag", &tensor, 1), ACL_ERROR_FAILURE);
80+ // 空指针/零 tensor 同样返回不支持
81+ EXPECT_EQ(acldumpSaveExceptionInfo(nullptr, nullptr, nullptr, 0), ACL_ERROR_FAILURE);
82+}
83+ 
84+TEST_F(TinyAdumpApiPlatformUtest, Test_acldumpGetExceptionInfoPath_NotSupport)
85+{
86+ char buf[64] = {0};
87+ EXPECT_EQ(acldumpGetExceptionInfoPath(buf, sizeof(buf)), ACL_ERROR_FAILURE);
88+ EXPECT_EQ(acldumpGetExceptionInfoPath(nullptr, 0), ACL_ERROR_FAILURE);
89+}