| @@ -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 | ## acldumpRegCallback | 400 | ## acldumpRegCallback |
| 397 | 401 | ||
| 398 | ```c | 402 | ```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 | ## acldumpType | 258 | ## acldumpType |
| 196 | 259 | ||
| 197 | ```c | 260 | ```c |
| 198 | -enum acldumpType { | 261 | +typedef enum acldumpType { |
| 199 | AIC_ERR_BRIEF_DUMP = 1, // 轻量化exception dump | 262 | 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 // 溢出算子Dump | 266 | 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 | ## aclmdlRICondTaskParams | 121 | ## 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 | |||
| 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 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 | # adump | 1 | # 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 | # adump | 1 | # 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 List | 5 | ## 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 | 16 | ||
| 17 | 17 | ||
| 18 | + | ||
| 18 | 19 | ||
| 19 | 20 | ||
| 21 | + | ||
| 20 | 22 | ||
| 21 | 23 | ||
| 22 | 24 | ||
| @@ -25,12 +27,12 @@ extern "C" { | |||
| 25 | 27 | ||
| 26 | 28 | ||
| 27 | typedef struct acldumpChunk { | 29 | typedef struct acldumpChunk { |
| 28 | - char fileName[ACL_DUMP_MAX_FILE_PATH_LENGTH]; // file name, absolute path | 30 | + char fileName[ACL_DUMP_MAX_FILE_PATH_LENGTH]; // name of the dump data file to be written, absolute path |
| 29 | - uint32_t bufLen; // dataBuf length | 31 | + uint32_t bufLen; // length of dataBuf, in bytes |
| 30 | - uint32_t isLastChunk; // is last chunk. 0: not 1: yes | 32 | + uint32_t isLastChunk; // whether it is the last chunk. 0: no, 1: yes |
| 31 | - int64_t offset; // Offset in file. -1: append write | 33 | + int64_t offset; // offset of the content in the dump data file. -1: append write |
| 32 | - int32_t flag; // flag | 34 | + int32_t flag; // reserved flag of the dump data, no flag is defined currently |
| 33 | - uint8_t dataBuf[0]; // data buffer | 35 | + uint8_t dataBuf[0]; // memory address of the dump data |
| 34 | } acldumpChunk; | 36 | } acldumpChunk; |
| 35 | 37 | ||
| 36 | ACL_DUMP_API aclError acldumpRegCallback(int32_t (*const messageCallback)(const acldumpChunk*, int32_t), int32_t flag); | 38 | ACL_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 | ||
| 64 | typedef enum acldumpType { | 66 | typedef enum acldumpType { |
| 65 | AIC_ERR_BRIEF_DUMP = 1, // lite exception dump | 67 | AIC_ERR_BRIEF_DUMP = 1, // lite exception dump |
| 66 | - AIC_ERR_NORM_DUMP = 2, // normal exception dump | 68 | + AIC_ERR_NORM_DUMP = 2, // normal exception dump, dumps shape/data type/format/attributes additionally |
| 67 | - AIC_ERR_DETAIL_DUMP = 3, // coredump mode | 69 | + AIC_ERR_DETAIL_DUMP = 3, // npu coredump dump, dumps AI Core internal memory, registers and call stack additionally |
| 68 | - DATA_DUMP = 4, // tensor data dump | 70 | + DATA_DUMP = 4, // model dump or single operator dump |
| 69 | - OVERFLOW_DUMP = 5 // overflow dump | 71 | + OVERFLOW_DUMP = 5 // overflow operator dump |
| 70 | } acldumpType; | 72 | } acldumpType; |
| 71 | 73 | ||
| 72 | /** | 74 | /** |
| @@ -80,6 +82,81 @@ typedef enum acldumpType { | |||
| 80 | */ | 82 | */ |
| 81 | ACL_FUNC_VISIBILITY const char* acldumpGetPath(acldumpType dumpType); | 83 | ACL_FUNC_VISIBILITY const char* acldumpGetPath(acldumpType dumpType); |
| 82 | 84 | ||
| 85 | + | ||
| 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 | 160 | ||
| 84 | } | 161 | } |
| 85 | 162 | ||
| @@ -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 problems | 121 | // 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 problems | 165 | // EP0006 Reasons - Invalid argument problems |
| 166 | constexpr const char* ADUMP_REASON_RESERVED_PARAM_MUST_EQUAL = "The parameter is reserved and can only be %s"; | 166 | constexpr const char* ADUMP_REASON_RESERVED_PARAM_MUST_EQUAL = "The parameter is reserved and can only be %s"; |
| 167 | constexpr const char* ADUMP_REASON_PARAM_PATH_EMPTY = "The parameter is a path and cannot be empty"; | 167 | constexpr 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"; | ||
| 168 | constexpr const char* ADUMP_REASON_PARAM_PATH_CREATE_DIR_ERROR = | 170 | constexpr 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 sequence | 179 | // EP0008 Reasons - Call API sequence |
| 174 | constexpr const char* ADUMP_REASON_API_CALLED_REPEATEDLY = "This API cannot be called repeatedly"; | 180 | constexpr 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 | ||
| 176 | constexpr const char* FUNC_NAME_ACL_OP_START_DUMP_ARGS = "aclopStartDumpArgs"; | 183 | constexpr const char* FUNC_NAME_ACL_OP_START_DUMP_ARGS = "aclopStartDumpArgs"; |
| 177 | constexpr const char* FUNC_ACL_OP_START_DUMP_ARGS_PARAM_PATH = "path"; | 184 | constexpr 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"; | |||
| 179 | constexpr const char* FUNC_NAME_ACL_DUMP_REG_CALLBACK = "acldumpRegCallback"; | 186 | constexpr const char* FUNC_NAME_ACL_DUMP_REG_CALLBACK = "acldumpRegCallback"; |
| 180 | constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_CLBK = "messageCallback"; | 187 | constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_CLBK = "messageCallback"; |
| 181 | constexpr const char* FUNC_ACL_DUMP_REG_CALLBACK_PARAM_FLAG = "flag"; | 188 | constexpr 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 Adx | 196 | } // namespace Adx |
| 183 | 197 | ||
| 184 | 198 | ||
| @@ -17,10 +17,28 @@ namespace Adx { | |||
| 17 | namespace { | 17 | namespace { |
| 18 | constexpr char DIRECTORY_SEPARATOR = '/'; | 18 | constexpr char DIRECTORY_SEPARATOR = '/'; |
| 19 | constexpr char FILE_EXTENSION_CHAR = '.'; | 19 | constexpr char FILE_EXTENSION_CHAR = '.'; |
| 20 | +constexpr const char *PARENT_DIR = ".."; | ||
| 20 | 21 | ||
| 21 | constexpr mmMode_t DEFAULT_DIR_MODE = M_IRUSR | M_IWUSR | M_IXUSR; | 22 | constexpr mmMode_t DEFAULT_DIR_MODE = M_IRUSR | M_IWUSR | M_IXUSR; |
| 22 | } // namespace | 23 | } // 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 | + | ||
| 24 | Path &Path::operator = (const std::string &path) | 42 | Path &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 | + | ||
| 178 | void Path::AppendPath(const std::string &path) | 263 | void 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 | ||
| 42 | private: | 71 | private: |
| 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 | 12 | ||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | + | ||
| 15 | 16 | ||
| 16 | 17 | ||
| 17 | 18 | ||
| @@ -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 | + | ||
| 38 | void DumpFile::SetInputTensors(const std::vector<DumpTensor> &inputTensors) | 48 | void 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) { | ||
| 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 | 155 | ||
| 109 | void DumpFile::SetMc2spaces(const std::vector<DumpWorkspace> &mc2Spaces) | 156 | void 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 | + | ||
| 115 | int32_t ExceptionDumper::ExceptionDumperInit(DumpType dumpType, const DumpConfig &dumpConfig) | 120 | int32_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; | ||
级别:一般 问题:SaveExceptionInfo 中调用了两次 rtGetDevice:第一次在 GetExceptionDumpPath 内部,第二次在 SaveExceptionInfo 本体中获取 devId 用于构造 DumpFile。 影响:冗余的 runtime 调用增加开销,且两次调用之间理论上可能因设备切换导致 deviceId 不一致(虽然实际场景中同一线程 deviceId 不会变化,但代码逻辑上存在不一致风险)。 修复建议:让 GetExceptionDumpPath 顺带返回 deviceId,或在 SaveExceptionInfo 中复用已获取的 deviceId,避免重复调用 rtGetDevice。 ![]() ![]() | |||
| 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 | + | ||
| 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 | + | ||
级别:一般 问题:时间戳后缀使用毫秒级 GetCurrentTimeWithMillisecond,若同一毫秒内多次调用 acldumpSaveExceptionInfo 且传入相同 fileName,将产生相同的最终文件路径。由于 DumpFile 以 M_APPEND 模式打开文件,多次调用的数据会被追加写入同一文件。 影响:高频调用场景下可能产生数据混叠,用户难以区分不同次落盘的数据。 修复建议:在时间戳基础上追加进程内自增序号或随机后缀以保证文件名唯一性,或在文档中明确说明同一毫秒内多次调用的行为约束。 ![]() ![]() | |||
| 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 | + | ||
| 261 | std::string ExceptionDumper::CreateExtraDumpPath() | 313 | std::string ExceptionDumper::CreateExtraDumpPath() |
| 262 | { | 314 | { |
| 263 | // Create extra dump path for tensor custom dump data | 315 | // 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 | ||
| 48 | private: | 52 | private: |
| 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_; |
级别:一般 问题:mutex_ 被改为 mutable 以便在 const 方法中加锁,但新增的 IsEnabledExceptionDump()、GetExceptionDumpPath() 和 SaveExceptionInfo() 均未获取 mutex_,而这些方法读取的 coredumpStatus_/exceptionStatus_/argsExceptionStatus_ 以及 dumpPath_ 可能被其他线程并发修改。 影响:在多线程场景下(例如一个线程调用 SaveExceptionInfo,另一个线程调用 ExceptionDumperInit 或 ExceptionModeDowngrade 修改状态),存在数据竞争,可能导致读取到不一致的状态或路径。 修复建议:在 IsEnabledExceptionDump()、GetExceptionDumpPath() 和 SaveExceptionInfo() 中通过 std::lock_guardstd::mutex 保护对共享成员的访问,与 mutex_ 被声明为 mutable 的意图保持一致。 ![]() ![]() | |||
| 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 Adx | 228 | } // namespace Adx |
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | 13 | ||
| 14 | 14 | ||
| 15 | + | ||
| 15 | 16 | ||
| 16 | namespace Adx { | 17 | namespace Adx { |
| 17 | enum class GeDataType: int32_t { | 18 | enum 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 Adx | 129 | } // namespace Adx |
| 128 | 130 | ||
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | + | ||
| 18 | 19 | ||
| 19 | namespace Adx { | 20 | namespace Adx { |
| 20 | uint64_t g_chunk[RING_CHUNK_SIZE + MAX_TENSOR_NUM] = {0}; | 21 | uint64_t g_chunk[RING_CHUNK_SIZE + MAX_TENSOR_NUM] = {0}; |
| @@ -23,6 +24,100 @@ static std::mutex g_setAssertMtx; | |||
| 23 | namespace { | 24 | namespace { |
| 24 | uint32_t g_atomicIndex = 0x2000; | 25 | uint32_t g_atomicIndex = 0x2000; |
| 25 | std::atomic<uint64_t> g_writeIdx{0}; | 26 | std::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 | } // namespace | 121 | } // namespace |
| 27 | 122 | ||
| 28 | void *AdumpGetSizeInfoAddr(uint32_t space, uint32_t &atomicIndex) | 123 | void *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); | ||
| 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 | 34 | ||
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 37 | 40 | ||
| 38 | 41 | ||
| 39 | namespace Adx { | 42 | namespace Adx { |
| @@ -683,6 +686,12 @@ void DumpManager::ExceptionModeDowngrade() | |||
| 683 | exceptionDumper_.ExceptionModeDowngrade(); | 686 | exceptionDumper_.ExceptionModeDowngrade(); |
| 684 | } | 687 | } |
| 685 | 688 | ||
| 689 | +bool DumpManager::IsEnabledExceptionDump() | ||
| 690 | +{ | ||
级别:提示 问题:DumpManager::IsEnabledExceptionDump() 未获取 resourceMtx_ 锁即调用 exceptionDumper_.IsEnabledExceptionDump(),而 GetExtraExceptionDumpPath 等方法在同一锁下操作 exceptionDumper_。 影响:与 ExceptionDumper 层面的线程安全问题叠加,锁策略不一致增加维护和理解成本。 修复建议:评估是否需要在 DumpManager 层面加锁,或统一在 ExceptionDumper 层面使用 mutex_ 保护所有公共方法。 ![]() ![]() | |||
| 691 | + std::lock_guard<std::mutex> lk(resourceMtx_); | ||
| 692 | + return exceptionDumper_.IsEnabledExceptionDump(); | ||
| 693 | +} | ||
| 694 | + | ||
| 686 | int32_t DumpManager::RegisterCallback(uint32_t moduleId, AdumpCallback enableFunc, AdumpCallback disableFunc) | 695 | int32_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 | + | ||
| 788 | int32_t DumpManager::SaveFile(const char* data, size_t dataLen, const char* fileName, SaveType type) | 810 | int32_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 | 10 | ||
| 11 | + | ||
| 11 | 12 | ||
| 12 | 13 | ||
| 13 | 14 | ||
| @@ -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 | 21 | ||
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | + | ||
| 24 | 25 | ||
| 25 | 26 | ||
| 26 | 27 | ||
| @@ -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 | +} | ||
级别:一般 问题: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 时的行为。 ![]() ![]() | |||
| 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 | + | ||
| 842 | TEST_F(AdumpApiUtest, Test_AdumpRegExceptionDumpCallback_Null) | 1118 | TEST_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 | +} | ||


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