同步等待
动态AIPP(单个动态AIPP输入)
视频课程
通过在线视频课程学习该功能,请参见AscendCL模型推理动态特性。
接口调用流程
动态AIPP场景下模型推理与基础推理应用的流程类似,都涉及AscendCL初始化与去初始化、运行管理资源申请与释放、模型构建、模型加载、模型执行、模型卸载等。
本节中重点描述动态AIPP场景下模型推理与基础推理应用的不同之处:
-
模型构建时,需配置动态AIPP相关参数:
构建模型时,需通过ATC工具的insert_op_conf参数配置动态AIPP模式。ATC工具的参数说明请参见《ATC工具使用指南》。
构建模型成功后,在生成的om模型中,会新增相应的输入(下文简称动态AIPP输入),在模型推理时通过该新增的输入提供具体的AIPP配置值。
例如,a输入的AIPP配置是动态的,在om模型中,会有与a对应的b输入来描述a的AIPP配置信息。在模型执行时,准备a输入的数据结构请参见准备模型执行的输入/输出数据结构,准备b输入的数据结构、设置b输入的数据请参见以下内容。
-
在执行模型推理前:
-
准备动态AIPP输入的数据结构:
-
申请动态AIPP输入对应的内存前,需要先调用aclmdlGetInputIndexByName接口根据输入名称(固定为ACL_DYNAMIC_AIPP_NAME)获取模型中标识该输入的index。
ACL_DYNAMIC_AIPP_NAME是一个宏,宏的定义如下:
#define ACL_DYNAMIC_AIPP_NAME "ascend_dynamic_aipp_data" -
调用aclmdlGetInputSizeByIndex根据index获取输入内存大小。
-
调用aclrtMalloc接口根据2中的大小申请内存。
申请动态AIPP输入对应的内存后,无需用户设置该内存中的数据(否则可能会导致业务异常),用户调用2中的接口后,系统会自动向该内存中填入数据。
-
调用aclCreateDataBuffer接口创建aclDataBuffer类型的数据,用于存放动态AIPP输入数据的内存地址、内存大小。
-
调用aclmdlCreateDataset接口创建aclmdlDataset类型的数据,并调用aclmdlAddDatasetBuffer接口向aclmdlDataset类型的数据中增加aclDataBuffer类型的数据。
-
-
设置动态AIPP参数值:
图1 接口调用流程

- 调用aclmdlGetInputIndexByName接口根据输入名称(固定为ACL_DYNAMIC_AIPP_NAME)获取模型中标识该输入的index。
- 设置动态AIPP参数值。
- 调用aclmdlCreateAIPP接口创建aclmdlAIPP类型。
- 根据实际需求,调用aclmdlAIPP数据类型下的操作接口设置动态AIPP参数值。
- 动态AIPP场景下,aclmdlSetAIPPSrcImageSize接口(设置原始图片的宽和高)必须调用。
- 调用aclmdlSetInputAIPP接口设置模型推理时的动态AIPP数据。
- 及时调用aclmdlDestroyAIPP接口销毁aclmdlAIPP类型。
-
示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br> | <br>// 1.模型加载,加载成功后,再设置动态AIPP参数值<br>// ......<br>// 2.准备模型描述信息modelDesc_,准备模型的输入数据input_和模型的输出数据output_<br>// 3.自定义函数,设置动态AIPP参数值<br>int ModelSetDynamicAIPP()<br>{<br> // 3.1 获取标识动态AIPP输入的index<br> size_t index;<br> // modelDesc_为aclmdlCreateDesc表示模型描述信息,根据1中加载成功的模型的ID,获取该模型的描述信息<br> aclError ret = aclmdlGetInputIndexByName(modelDesc_, ACL_DYNAMIC_AIPP_NAME, &index);<br> // 3.2 设置动态AIPP参数值<br> uint64_t batchNumber = 1;<br> aclmdlAIPP *aippDynamicSet = aclmdlCreateAIPP(batchNumber);<br> ret = aclmdlSetAIPPSrcImageSize(aippDynamicSet, 256, 224);<br> ret = aclmdlSetAIPPInputFormat(aippDynamicSet, ACL_YUV420SP_U8);<br> ret = aclmdlSetAIPPCscParams(aippDynamicSet, 1, 256, 443, 0, 256, -86, -178, 256, 0, 350, 0, 0, 0, 0, 128, 128);<br> ret = aclmdlSetAIPPRbuvSwapSwitch(aippDynamicSet, 0);<br> ret = aclmdlSetAIPPDtcPixelMean(aippDynamicSet, 0, 0, 0, 0, 0);<br> ret = aclmdlSetAIPPDtcPixelMin(aippDynamicSet, 0, 0, 0, 0, 0);<br> ret = aclmdlSetAIPPPixelVarReci(aippDynamicSet, 1.0, 1.0, 1.0, 1.0, 0);<br> ret = aclmdlSetAIPPCropParams(aippDynamicSet, 1, 2, 2, 224, 224, 0);<br> ret = aclmdlSetInputAIPP(modelId_, input_, index, aippDynamicSet);<br> ret = aclmdlDestroyAIPP(aippDynamicSet);<br> <br> // ......<br>}<br>// 4.自定义函数,执行模型<br>int ModelExecute(int index)<br>{<br> aclError ret;<br> // 4.1 调用自定义函数,设置动态AIPP参数值<br> ret = ModelSetDynamicAIPP();<br> // 4.2 执行模型,modelId_表示加载成功的模型的ID,input_和output_分别表示模型的输入和输出<br> ret = aclmdlExecute(modelId_, input_, output_);<br> // ......<br>}<br>// 5.处理模型推理结果<br>// TODO<br> |
|---|
父主题: 模型动态AIPP推理
动态AIPP(多个动态AIPP输入)
接口调用流程
模型有多个动态AIPP输入时的推理基本流程与单个动态AIPP输入类似,请参见动态AIPP(单个动态AIPP输入)。
多个动态AIPP输入与单个动态AIPP输入的不同点如下:
- 需调用aclmdlGetAippType接口查询指定模型的指定输入是否有关联的动态AIPP输入,若有,则输出标识动态AIPP输入的index,该参数值可作为aclmdlSetAIPPByInputIndex接口的入参之一,来设置对应输入上的动态AIPP参数值。
- 为避免在错误的输入上设置动态AIPP参数,用户可调用aclmdlGetInputNameByIndex接口先获取指定输入index的输入名称,根据输入名称所对应的index设置动态AIPP参数。
示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br> | cpp<br>// 1.模型加载,加载成功后,再设置动态AIPP参数值<br>// ......<br>// 2.准备模型描述信息modelDesc_,准备模型的输入数据input_和模型的输出数据output_<br>// ......<br>// 3.自定义函数,设置动态AIPP参数值<br>int ModelSetDynamicAIPP()<br>{<br> // 3.1 获取标识动态AIPP输入的index<br> std::vector<size_t> dataNeedDynamicAipp;<br> for (size_t index = 0; index < aclmdlGetNumInputs(modelDesc_); ++index) {<br> aclmdlInputAippType aippType;<br> size_t dynamicAttachedDataIndex;<br> aclError ret = aclmdlGetAippType(modelId_, index, &aippType, &dynamicAttachedDataIndex);<br> if (aippType == ACL_DATA_WITH_DYNAMIC_AIPP) {<br> dataNeedDynamicAipp.push_back(index);<br> }<br> }<br> // 3.2 当前示例中以2个动态AIPP输入为例,用户可根据实际情况修改<br> if (dataNeedDynamicAipp.size() != 2) {<br> return -1;<br> }<br> // 创建第一个动态aipp配置参数<br> uint64_t batchNumber1 = 1;<br> aclmdlAIPP *aippDynamicSet1 = aclmdlCreateAIPP(batchNumber1);<br> ret = aclmdlSetAIPPSrcImageSize(aippDynamicSet1, 256, 224);<br> ret = aclmdlSetAIPPInputFormat(aippDynamicSet1, ACL_YUV420SP_U8);<br> ret = aclmdlSetAIPPCscParams(aippDynamicSet1, 1, 256, 443, 0, 256, -86, -178, 256, 0, 350, 0, 0, 0, 0, 128, 128);<br> ret = aclmdlSetAIPPRbuvSwapSwitch(aippDynamicSet1, 0);<br> ret = aclmdlSetAIPPDtcPixelMean(aippDynamicSet1, 0, 0, 0, 0, 0);<br> ret = aclmdlSetAIPPDtcPixelMin(aippDynamicSet1, 0, 0, 0, 0, 0);<br> ret = aclmdlSetAIPPPixelVarReci(aippDynamicSet1, 1.0, 1.0, 1.0, 1.0, 0);<br> ret = aclmdlSetAIPPCropParams(aippDynamicSet1, 1, 2, 2, 224, 224, 0);<br> // 设置模型推理时的动态aipp参数值<br> ret = aclmdlSetAIPPByInputIndex(modelId_, input_, dataNeedDynamicAipp[0], aippDynamicSet1);<br> ret = aclmdlDestroyAIPP(aippDynamicSet1);<br> // 创建第二个动态aipp配置参数<br> uint64_t batchNumber2 = 2;<br> aclmdlAIPP *aippDynamicSet2 = aclmdlCreateAIPP(batchNumber2);<br> ret = aclmdlSetAIPPSrcImageSize(aippDynamicSet2, 224, 224);<br> // 此处可以继续调用其它AIPP参数设置接口<br> // 设置模型推理时的动态aipp参数值<br> ret = aclmdlSetAIPPByInputIndex(modelId_, input_, dataNeedDynamicAipp[1], aippDynamicSet2);<br> ret = aclmdlDestroyAIPP(aippDynamicSet2);<br>}<br>// 4.自定义函数,执行模型<br>int ModelExecute(int index)<br>{<br> aclError ret;<br> // 4.1 调用自定义函数,设置动态AIPP参数值<br> ret = ModelSetDynamicAIPP();<br> // 4.2 执行模型,modelId_表示加载成功的模型的ID,input_和output_分别表示模型的输入和输出<br> ret = aclmdlExecute(modelId_, input_, output_);<br> // ......<br>}<br>// 5.处理模型推理结果<br>// TODO<br> |
|---|
父主题: 模型动态AIPP推理
Stream管理
在AscendCL中,Stream是一个任务队列,应用程序通过Stream来管理任务的并行,一个Stream内部的任务保序执行,即Stream根据发送过来的任务依次执行;不同Stream中的任务并行执行。一个默认Context下会挂一个默认Stream,如果不显式创建Stream,可使用默认Stream。默认Stream作为接口入参时,直接传NULL。
AscendCL提供以下几种Stream管理机制,其中,多Stream场景下的同步等待流程请参见多Stream时的同步等待流程:
单线程单Stream
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br> | cpp<br>#include "acl/acl.h"<br>// ......<br>// 显式创建一个Stream<br>aclrtStream stream;<br>aclrtCreateStream(&stream);<br>// 调用触发任务的接口,传入stream参数<br>aclrtMemcpyAsync(dstPtr, dstSize, srcPtr, srcSize, ACL_MEMCPY_HOST_TO_DEVICE, stream);<br>// 调用aclrtSynchronizeStream接口,阻塞应用程序运行,直到指定Stream中的所有任务都完成。<br>aclrtSynchronizeStream(stream);<br>// Stream使用结束后,显式销毁Stream<br>aclrtDestroyStream(stream);<br>// ......<br> |
|---|
单线程多Stream
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br> | cpp<br>#include "acl/acl.h"<br>// ......<br>int32_t deviceId = 0 ;<br>uint32_t modelId1 = 0;<br>uint32_t modelId2 = 1;<br>aclrtContext context;<br>aclrtStream stream1;<br>aclrtStream stream2;<br>// 如果只创建了一个Context,线程默认将这个Context作为线程当前的Context;<br>// 如果是多个Context,则需要调用aclrtSetCurrentContext接口设置当前线程的Context<br> aclrtCreateContext(&context, deviceId);<br> aclrtCreateStream(&stream1);<br>// 调用触发任务的接口,例如异步模型推理,任务下发在stream1<br>aclmdlDataset *input1;<br>aclmdlDataset *output1;<br>aclmdlExecuteAsync(modelId1, input1, output1, stream1);<br>aclrtCreateStream(&stream2);<br>// 调用触发任务的接口,例如异步模型推理, 任务下发在stream2<br>aclmdlDataset *input2;<br>aclmdlDataset *output2;<br>aclmdlExecuteAsync(modelId2, input1, output2, stream2);<br>// 流同步<br>aclrtSynchronizeStream(stream1);<br>aclrtSynchronizeStream(stream2);<br>// 释放资源<br>aclrtDestroyStream(stream1);<br>aclrtDestroyStream(stream2);<br>aclrtDestroyContext(context);<br>// ....<br> |
|---|
多线程多Stream
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br> | cpp<br>#include "acl/acl.h"<br>// ......<br>void runThread(aclrtStream stream) {<br> int32_t deviceId =0 ;<br> aclrtContext context;<br> // 如果只创建了一个Context,线程默认将这个Context作为线程当前的Context;<br> // 如果是多个Context,则需要调用aclrtSetCurrentContext接口设置当前线程的Context<br> aclrtCreateContext(&context, deviceId);<br> aclrtCreateStream(&stream);<br> // 调用触发任务的接口<br> // ....<br> // 释放资源<br> aclrtDestroyStream(stream);<br> aclrtDestroyContext(context);<br> <br>}<br>aclrtStream stream1;<br>aclrtStream stream2;<br>// 创建2个线程,每个线程对应一个Stream<br>std::thread t1(runThread, stream1);<br>std::thread t2(runThread, stream2);<br>// 显式调用join函数确保结束线程<br>t1.join();<br>t2.join();<br> |
|---|
多Stream时的同步等待流程
开发应用时,如果涉及多Stream之间的任务等待,则应用程序中必须包含相关的代码逻辑,关于该场景的接口调用流程,请依次参见AscendCL接口调用流程以及本节中的说明。
图1 同步等待流程_多Stream场景

多Stream之间任务的同步等待可以利用Event实现,调用aclrtStreamWaitEvent接口阻塞指定Stream的运行,直到指定的Event完成。需在调用aclrtStreamWaitEvent接口前,先调用aclrtRecordEvent接口。调用示例请参见Stream间任务的同步等待示例代码。
模型加载与执行的流程请参见基础推理应用。
算子加载与执行的流程请参见单算子调用。
父主题: 扩展更多特性
同步等待
视频课程
通过在线视频课程学习该功能,请参见AscendCL同步&异步特性。
同步机制
AscendCL提供以下几种同步机制:
- Event的同步等待示例代码:调用aclrtSynchronizeEvent接口,阻塞应用程序运行,等待Event完成。
- Stream内任务的同步等待示例代码:调用aclrtSynchronizeStream接口,阻塞应用程序运行,直到指定Stream中的所有任务都完成。
- Stream间任务的同步等待示例代码:调用aclrtStreamWaitEvent接口,阻塞指定Stream的运行,直到指定的Event完成。支持多个Stream等待同一个Event的场景。接口调用流程请参见多Stream时的同步等待流程。
- Device的同步等待示例代码:调用aclrtSynchronizeDevice接口,阻塞应用程序运行,直到正在运算中的Device完成运算。
Event的同步等待示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
#include "acl/acl.h"
// ......
// 创建一个Event
aclrtEvent event;
aclrtCreateEvent(&event);
// 创建一个Stream
aclrtStream stream;
aclrtCreateStream(&stream);
// stream末尾添加了一个event
aclrtRecordEvent(event, stream);
// 阻塞应用程序运行,等待event发生,也就是stream执行完成
// stream完成后产生event,唤醒执行应用程序的控制流,开始执行程序
aclrtSynchronizeEvent(event);
// 显式销毁资源
aclrtDestroyStream(stream);
aclrtDestroyEvent(event);
// ......
Stream内任务的同步等待示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br> | cpp<br>#include "acl/acl.h"<br>// ......<br>// 显式创建一个Stream<br>aclrtStream stream;<br>aclrtCreateStream(&stream);<br>// 调用触发任务的接口,传入stream参数<br>aclrtMemcpyAsync(dstPtr, dstSize, srcPtr, srcSize, ACL_MEMCPY_HOST_TO_DEVICE, stream);<br>// 调用aclrtSynchronizeStream接口,阻塞应用程序运行,直到指定Stream中的所有任务都完成。<br>aclrtSynchronizeStream(stream);<br>// Stream使用结束后,显式销毁Stream<br>aclrtDestroyStream(stream);<br>// ......<br> |
|---|
Stream间任务的同步等待示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br> | cpp<br>#include "acl/acl.h"<br>// ......<br>// 创建一个Event<br>aclrtEvent event;<br>aclrtCreateEvent(&event);<br>// 创建两个Stream<br>aclrtStream s1;<br>aclrtStream s2;<br>aclrtCreateStream(&s1);<br>aclrtCreateStream(&s2);<br>// 在s1末尾添加了一个event<br>aclrtRecordEvent(event, s1);<br>// 阻塞s2运行,直到指定event发生,也就是s1执行完成<br>// s1完成后,唤醒s2,继续执行s2的任务<br>aclrtStreamWaitEvent(s2, event);<br>// 显式销毁资源<br>aclrtDestroyStream(s2);<br>aclrtDestroyStream(s1);<br>aclrtDestroyEvent(event);<br>// ......<br> |
|---|
Device的同步等待示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br> | cpp<br>#include "acl/acl.h"<br>// ......<br>// 指定device<br>aclrtSetDevice(0);<br>// 创建context<br>aclrtContext ctx;<br>aclrtCreateContext(&ctx, 0);<br>// 创建stream<br>aclrtStream stream;<br>aclrtCreateStream(&stream);<br>// 阻塞应用程序运行,直到正在运算中的Device完成运算<br>aclrtSynchronizeDevice();<br>// 资源销毁<br>aclrtDestroyStream(stream);<br>aclrtDestroyContext(ctx);<br>aclrtResetDevice(0);<br> |
|---|
父主题: 扩展更多特性
AI Core异常信息获取
基本原理
使用场景****举例:执行整网模型推理时,如果产生AI Core报错,可以调用本接口获取报错算子的描述信息,再做进一步错误排查。
推荐的接口调用顺序如下:
-
定义并实现异常回调函数fn(aclrtExceptionInfoCallback类型),回调函数原型请参见aclrtSetExceptionInfoCallback 。
实现回调函数的关键步骤如下:
-
在异常回调函数fn内调用aclrtGetDeviceIdFromExceptionInfo、aclrtGetStreamIdFromExceptionInfo、aclrtGetTaskIdFromExceptionInfo接口分别获取Device ID、Stream ID、Task ID。
-
在异常回调函数fn内调用aclmdlCreateAndGetOpDesc接口获取算子的描述信息。
-
在异常回调函数fn内调用aclGetTensorDescByIndex接口获取指定算子输入/输出的tensor描述。
-
在异常回调函数fn内如下接口获取tensor描述中的数据,进行进一步分析。
例如,调用aclGetTensorDescAddress接口获取tensor数据的内存地址(用户可从该内存地址中获取tensor数据)、调用aclGetTensorDescType接口获取tensor描述中的数据类型、调用aclGetTensorDescFormat接口获取tensor描述中的Format、调用aclGetTensorDescNumDims接口获取tensor描述中的Shape维度个数、调用aclGetTensorDescDimV2接口获取Shape中指定维度的大小。
-
-
调用aclrtSetExceptionInfoCallback接口设置异常回调函数。
-
执行模型推理。
如果存在AI Core报错,则触发回调函数fn,获取算子的信息,进行进一步分析。
示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
本节中的示例重点介绍AI Core异常信息获取的代码逻辑,AscendCL初始化和去初始化请参见AscendCL初始化与去初始化,运行管理资源申请与释放请参见运行管理资源申请与释放,模型加载、准备模型推理的输入/输出数据的接口调用流程、模型执行、模型卸载等请参见模型推理。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br> | <br>// 1.AscendCL初始化<br>// 2.申请运行管理资源,包括设置用于计算的Device、创建Context、创建Stream<br>// 3.模型加载,加载成功后,返回标识模型的modelId<br>// 4.创建aclmdlDataset类型的数据,用于描述模型的输入数据input、输出数据output<br>// 5.实现异常回调函数<br>void callback(aclrtExceptionInfo *exceptionInfo)<br>{<br> deviceId = aclrtGetDeviceIdFromExceptionInfo(exceptionInfo);<br> streamId = aclrtGetStreamIdFromExceptionInfo(exceptionInfo);<br> taskId = aclrtGetTaskIdFromExceptionInfo(exceptionInfo);<br> <br> char opName[256];<br> aclTensorDesc *inputDesc = nullptr;<br> aclTensorDesc *outputDesc = nullptr;<br> size_t inputCnt = 0;<br> size_t outputCnt = 0; <br> // 用户可以将获取的算子信息写入到文件,或者另起线程,当发生异常回调时触发线程处理函数,在线程处理函数中将算子信息在屏幕上显示 <br> aclmdlCreateAndGetOpDesc(deviceId, streamId, taskId, opName, 256, &inputDesc, &inputCnt, &outputDesc, &outputCnt);<br> // 可以调用AscendCL tensor的相关接口,获取算子的相关信息,用户可以根据自己需要调用<br> for (size_t i = 0; i < inputCnt; ++i) {<br> const aclTensorDesc *desc = aclGetTensorDescByIndex(inputDesc, i);<br> aclGetTensorDescAddress(desc);<br> aclGetTensorDescFormat(desc);<br> }<br> for (size_t i = 0; i < outputCnt; ++i) {<br> const aclTensorDesc *desc = aclGetTensorDescByIndex(outputDesc, i);<br> aclGetTensorDescAddress(desc);<br> aclGetTensorDescFormat(desc);<br> }<br> aclDestroyTensorDesc(inputDesc);<br> aclDestroyTensorDesc(outputDesc);<br>}<br>// 6.设置异常回调<br>aclrtSetExceptionInfoCallback(callback);<br>// 7.执行模型<br>ret = aclmdlExecute(modelId, input, output);<br>// 8.处理模型推理结果<br>// 9.释放描述模型输入/输出信息、内存等资源,卸载模型<br>// 10.释放运行管理资源<br>// 11. AscendCL去初始化<br>// ......<br> |
|---|
父主题: 扩展更多特性
Profiling性能数据采集
基本原理
该章节下的接口用于Profiling采集性能数据,实现方式支持以下三种:
-
Profiling AscendCL API(通过Profiling AscendCL API采集并落盘性能数据)
实现将采集到的Profiling数据写入文件,再使用Profiling工具解析该文件(请参见《性能分析工具使用指南》下的“数据解析与导出”),并展示性能分析数据。
包括以下两种接口调用方式:
-
aclprofInit接口、aclprofStart接口、aclprofStop接口、aclprofFinalize接口配合使用,实现该方式的性能数据采集。该方式可获取AscendCL的接口性能数据、AI Core上算子的执行时间、AI Core性能指标数据等。目前这些接口为进程级控制,表示在进程内任意线程调用该接口,其它线程都会生效。
一个进程内,可以根据需求多次调用这些接口,基于不同的Profiling采集配置,采集数据。
-
调用aclInit接口,在AscendCL初始化阶段,通过*.json 文件传入要采集的Profiling数据。该方式可获取AscendCL的接口性能数据、AI Core上算子的执行时间、AI Core性能指标数据等。
一个进程内,只能调用一次aclInit接口,如果要修改Profiling采集配置,需修改*.json文件中的配置。详细使用说明请参见aclInit接口处的说明,不在本章节描述。
-
-
Profiling AscendCL API for Extension(Profiling AscendCL API扩展接口)
当用户需要定位应用程序或上层框架程序的性能瓶颈时,可在Profiling采集进程内(aclprofStart接口与aclprofStop接口之间)调用Profiling AscendCL API扩展接口(统称为msproftx功能),开启记录应用程序执行期间特定事件发生的时间跨度,并将数据写入Profiling数据文件,再使用Profiling工具解析该文件,并导出展示性能分析数据。
一个进程内,可以根据需求多次调用这些接口,接口调用方式如下:在aclprofStart和aclprofStop接口之间调用aclprofCreateStamp、aclprofPush、aclprofPop、aclprofRangeStart、aclprofRangeStop、aclprofDestroyStamp接口。该方式可获取应用程序执行期间特定时间发生的事件并记录事件发生的时间跨度。
Profiling工具解析导出操作请参见《性能分析工具使用指南》下的“Profiling数据解析”和“Profiling数据导出”。
-
Profiling AscendCL API for Subscription(订阅算子信息的Profiling AscendCL API)
实现将采集到的Profiling数据解析后写入管道,由用户读入内存,再由用户调用AscendCL的接口获取性能数据。
接口调用方式:aclprofModelSubscribe接口、aclprofGet*接口、aclprofModelUnSubscribe接口配合使用,实现该方式的性能数据采集,当前支持获取网络模型中算子的性能数据,包括算子名称、算子类型名称、算子执行时间等。
Profiling AscendCL API示例代码
调用接口后,需增加异常处理的分支,示例代码中不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
本节中的示例重点介绍Profiling性能数据采集的代码逻辑,AscendCL初始化和去初始化请参见AscendCL初始化与去初始化,运行管理资源申请与释放请参见运行管理资源申请与释放,模型加载、准备模型推理的输入/输出数据的接口调用流程、模型执行、模型卸载等请参见模型推理。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br> | <br>// 1.AscendCL初始化<br>// 2.申请运行管理资源,包括设置用于计算的Device、创建Context、创建Stream<br>// 3.profiling初始化<br>// 设置数据落盘路径<br>const char *aclProfPath = "...";<br>aclprofInit(aclProfPath, strlen(aclProfPath));<br>// 4.进行profiling配置<br>uint32_t deviceIdList[1] = {0};<br>// 创建配置结构体<br>aclprofConfig *config = aclprofCreateConfig(deviceIdList, 1, ACL_AICORE_ARITHMETIC_UTILIZATION, <br> nullptr,ACL_PROF_ACL_API | ACL_PROF_TASK_TIME | ACL_PROF_AICORE_METRICS | ACL_PROF_AICPU | ACL_PROF_HCCL_TRACE | ACL_PROF_MSPROFTX | ACL_PROF_RUNTIME_API);<br>const char *memFreq = "15";<br>ret = aclprofSetConfig(ACL_PROF_SYS_HARDWARE_MEM_FREQ, memFreq, strlen(memFreq));<br>aclprofStart(config);<br>// 5.模型加载,加载成功后,返回标识模型的modelId<br>// 6.创建aclmdlDataset类型的数据,用于描述模型的输入数据input、输出数据output<br> <br>// 7.执行模型<br>ret = aclmdlExecute(modelId, input, output);<br>// 8.处理模型推理结果<br>// 9.释放描述模型输入/输出信息、内存等资源,卸载模型<br>// 10.关闭profiling配置, 释放配置资源, 释放profiling组件资源<br>aclprofStop(config);<br>aclprofDestroyConfig(config);<br>aclprofFinalize();<br>// 11.释放运行管理资源<br>// 12. AscendCL去初始化<br>// ......<br> |
|---|
Profiling AscendCL API for Extension示例代码
调用接口后,需增加异常处理的分支,示例代码中不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
Profiling msproftx接口,请参见如下示例中的加粗部分代码。。
示例一(aclprofMark示例):
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br> | <br>//1.AscendCL初始化<br>//2.申请运行管理资源,包括设置用于计算的Device、创建Context、创建Stream<br>stamp = aclprofCreateStamp();<br>aclprofSetStampTraceMessage(stamp, "aclrtCreateStream_mark", strlen("AscendCL_Init_Mark"));<br>aclprofMark(stamp); //标记Create Stream事件<br>aclprofDestroyStamp(stamp);<br>ret = aclrtCreateStream(&stream_);<br>//3..Profiling初始化<br>//设置数据落盘路径<br>const char *aclProfPath = "...";<br>aclprofInit(aclProfPath, strlen(aclProfPath));<br>//4.进行Profiling配置<br>uint32_t deviceIdList[1] = {0};<br>//创建配置结构体<br>aclprofConfig *config = aclprofCreateConfig(deviceIdList, 1, ACL_AICORE_ARITHMETIC_UTILIZATION, <br> nullptr,ACL_PROF_ACL_API | ACL_PROF_TASK_TIME);<br>const char *memFreq = "15";<br>ret = aclprofSetConfig(ACL_PROF_SYS_HARDWARE_MEM_FREQ, memFreq, strlen(memFreq));<br>aclprofStart(config);<br>aclprofStepInfo *stepInfo = aclprofCreateStepInfo();<br>int ret = aclprofGetStepTimestamp(stepInfo, ACL_STEP_START, stream_);<br>//5.模型加载,加载成功后,返回标识模型的modelId<br>stamp = aclprofCreateStamp();<br>aclprofSetStampTraceMessage(stamp, "model_load_mark", strlen("model_load_mark"));<br>aclprofMark(stamp); //标记模型加载事件<br>aclprofDestroyStamp(stamp);<br>//6.创建aclmdlDataset类型的数据,用于描述模型的输入数据input、输出数据output<br>//7.执行模型<br>ret = aclmdlExecute(modelId, input, output);<br>//8.处理模型推理结果<br>//9.释放描述模型输入/输出信息、内存等资源,卸载模型<br>int ret = aclprofGetStepTimestamp(stepInfo, ACL_STEP_END, stream_);<br>aclprofDestroyStepInfo(stepInfo);<br>//10.关闭Profiling配置, 释放配置资源, 释放Profiling组件资源<br>aclprofStop(config);<br>aclprofDestroyConfig(config);<br>aclprofFinalize();<br>//11.释放运行管理资源<br>//12. AscendCL去初始化<br>//......<br> |
|---|
示例二(aclprofPush/aclprofPop示例,适用于单线程):
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br> | <br>//1.AscendCL初始化<br>//2.申请运行管理资源,包括设置用于计算的Device、创建Context、创建Stream<br>ret = aclrtCreateStream(&stream_);<br>//3..Profiling初始化<br>//设置数据落盘路径<br>const char *aclProfPath = "...";<br>aclprofInit(aclProfPath, strlen(aclProfPath));<br>//4.进行Profiling配置<br>uint32_t deviceIdList[1] = {0};<br>//创建配置结构体<br>aclprofConfig *config = aclprofCreateConfig(deviceIdList, 1, ACL_AICORE_ARITHMETIC_UTILIZATION, <br> nullptr,ACL_PROF_ACL_API | ACL_PROF_TASK_TIME);<br>const char *memFreq = "15";<br>ret = aclprofSetConfig(ACL_PROF_SYS_HARDWARE_MEM_FREQ, memFreq, strlen(memFreq));<br>aclprofStart(config);<br>aclprofStepInfo *stepInfo = aclprofCreateStepInfo();<br>int ret = aclprofGetStepTimestamp(stepInfo, ACL_STEP_START, stream_);<br>//5.模型加载,加载成功后,返回标识模型的modelId<br>//6.创建aclmdlDataset类型的数据,用于描述模型的输入数据input、输出数据output<br>//7.执行模型(模型仅在单线程执行)<br>stamp = aclprofCreateStamp();<br>aclprofSetStampTraceMessage(stamp, "aclmdlExecute_duration", strlen("aclmdlExecute_duration"));<br>aclprofPush(stamp);<br>ret = aclmdlExecute(modelId, input, output);<br>aclprofPop(stamp);<br>aclprofDestroyStamp(stamp);<br>//8.处理模型推理结果<br>//9.释放描述模型输入/输出信息、内存等资源,卸载模型<br>int ret = aclprofGetStepTimestamp(stepInfo, ACL_STEP_END, stream_);<br>aclprofDestroyStepInfo(stepInfo);<br>//10.关闭Profiling配置, 释放配置资源, 释放Profiling组件资源<br>aclprofStop(config);<br>aclprofDestroyConfig(config);<br>aclprofFinalize();<br>//11.释放运行管理资源<br>//12. AscendCL去初始化<br>//......<br> |
|---|
示例三(aclprofRangeStart/aclprofRangeStop示例,适用于单线程或跨线程):
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br> | <br>//1.AscendCL初始化<br>//2.申请运行管理资源,包括设置用于计算的Device、创建Context、创建Stream<br>ret = aclrtCreateStream(&stream_);<br>//3..Profiling初始化<br>//设置数据落盘路径<br>const char *aclProfPath = "...";<br>aclprofInit(aclProfPath, strlen(aclProfPath));<br>//4.进行Profiling配置<br>uint32_t deviceIdList[1] = {0};<br>//创建配置结构体<br>aclprofConfig *config = aclprofCreateConfig(deviceIdList, 1, ACL_AICORE_ARITHMETIC_UTILIZATION, <br> nullptr,ACL_PROF_ACL_API | ACL_PROF_TASK_TIME);<br>const char *memFreq = "15";<br>ret = aclprofSetConfig(ACL_PROF_SYS_HARDWARE_MEM_FREQ, memFreq, strlen(memFreq));<br>aclprofStart(config);<br>aclprofStepInfo *stepInfo = aclprofCreateStepInfo();<br>int ret = aclprofGetStepTimestamp(stepInfo, ACL_STEP_START, stream_);<br>//5.模型加载,加载成功后,返回标识模型的modelId<br>//6.创建aclmdlDataset类型的数据,用于描述模型的输入数据input、输出数据output<br>//7.执行模型(模型在跨线程执行)<br>stamp = aclprofCreateStamp();<br>aclprofSetStampTraceMessage(stamp, "aclmdlExecute_duration", strlen("aclmdlExecute_duration"));<br>aclprofRangeStart(stamp, &rangeId);<br>ret = aclmdlExecute(modelId, input, output);<br>aclprofRangeStop(rangeId);<br>aclprofDestroyStamp(stamp);<br>//8.处理模型推理结果<br>//9.释放描述模型输入/输出信息、内存等资源,卸载模型<br>int ret = aclprofGetStepTimestamp(stepInfo, ACL_STEP_END, stream_);<br>aclprofDestroyStepInfo(stepInfo);<br>//10.关闭Profiling配置, 释放配置资源, 释放Profiling组件资源<br>aclprofStop(config);<br>aclprofDestroyConfig(config);<br>aclprofFinalize();<br>//11.释放运行管理资源<br>//12. AscendCL去初始化<br>//......<br> |
|---|
Profiling AscendCL API for Subscription示例代码
调用接口后,需增加异常处理的分支,并记录报错日志、提示日志,此处不一一列举。以下是关键步骤的代码示例,不可以直接拷贝编译运行,仅供参考。
本节中的示例重点介绍Profiling性能数据采集的代码逻辑,AscendCL初始化和去初始化请参见AscendCL初始化与去初始化,运行管理资源申请与释放请参见运行管理资源申请与释放,模型加载、准备模型推理的输入/输出数据的接口调用流程、模型执行、模型卸载等请参见模型推理。
<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br>10<br>11<br>12<br>13<br>14<br>15<br>16<br>17<br>18<br>19<br>20<br>21<br>22<br>23<br>24<br>25<br>26<br>27<br>28<br>29<br>30<br>31<br>32<br>33<br>34<br>35<br>36<br>37<br>38<br>39<br>40<br>41<br>42<br>43<br>44<br>45<br>46<br>47<br>48<br>49<br>50<br>51<br>52<br>53<br>54<br>55<br>56<br>57<br>58<br>59<br>60<br>61<br>62<br>63<br>64<br>65<br>66<br>67<br>68<br>69<br>70<br>71<br>72<br>73<br>74<br>75<br>76<br>77<br>78<br>79<br>80<br>81<br>82<br>83<br>84<br>85<br>86<br>87<br>88<br>89<br>90<br>91<br>92<br>93<br>94<br> | <br>// 1.AscendCL初始化<br>// 2.申请运行管理资源,包括设置用于计算的Device、创建Context、创建Stream<br>// 3.模型加载,加载成功后,返回标识模型的modelId<br>// 4.创建aclmdlDataset类型的数据,用于描述模型的输入数据input、输出数据output<br>// 5.创建管道(UNIX操作系统下需要引用C++标准库头文件unistd.h),用于读取以及写入模型订阅的数据<br>int subFd[2];<br>// 读管道指针指向subFd[0],写管道指针指向subFd[1] <br>pipe(subFd);<br>// 6.创建模型订阅的配置并且进行模型订阅<br>aclprofSubscribeConfig *config = aclprofCreateSubscribeConfig(1, ACL_AICORE_NONE, &subFd[1]);<br>// 模型订阅需要传入模型的modelId<br>aclprofModelSubscribe(modelId, config);<br>// 7.实现管道读取订阅数据的函数<br>// 7.1 自定义函数,实现从用户内存中读取订阅数据的函数<br>void getModelInfo(void *data, uint32_t len) {<br> uint32_t opNumber = 0;<br> uint32_t dataLen = 0;<br> // 通过AscendCL接口读取算子信息个数<br> aclprofGetOpNum(data, len, &opNumber);<br> // 遍历用户内存的算子信息<br> for (int32_t i = 0; i < opNumber; i++){<br> // 获取算子的模型id<br> uint32_t modelId = aclprofGetModelId(data,len, i);<br> // 获取算子的类型名称长度<br> size_t opTypeLen = 0;<br> aclprofGetOpTypeLen(data, len, i, &opTypeLen);<br> // 获取算子的类型名称<br> char opType[opTypeLen];<br> aclprofGetOpType(data, len, i, opType, opTypeLen);<br> // 获取算子的详细名称长度<br> size_t opNameLen = 0;<br> aclprofGetOpNameLen(data, len, i, &opNameLen);<br> // 获取算子的详细名称<br> char opName[opNameLen];<br> aclprofGetOpName(data, len, i, opName, opNameLen);<br> // 获取算子的执行开始时间<br> uint64_t opStart = aclprofGetOpStart(data, len, i);<br> // 获取算子的执行结束时间<br> uint64_t opEnd = aclprofGetOpEnd(data, len, i);<br> uint64_t opDuration = aclprofGetOpDuration(data, len, i);<br> }<br>}<br>// 7.2 自定义函数,实现从管道中读取数据到用户内存的函数<br>void *profDataRead(void *fd) {<br> // 设置每次从管道中读取的算子信息个数<br> uint64_t N = 10;<br> // 获取单位算子信息的大小(Byte)<br> uint64_t bufferSize = 0;<br> aclprofGetOpDescSize(&bufferSize);<br> // 计算存储算子信息的内存的大小,并且申请内存<br> uint64_t readbufLen = bufferSize * N;<br> char *readbuf = new char[readbufLen];<br> // 从管道中读取数据到申请的内存中,读取到的实际数据大小dataLen可能小于bufferSize * N,如果管道中没有数据,默认会阻塞直到读取到数据为止<br> auto dataLen = read(*(int*)fd, readbuf, readbufLen);<br> // 读取数据到readbuf成功<br> while (dataLen > 0) {<br> // 调用5.1实现的函数解析内存中的数据<br> getModelInfo(readbuf, dataLen);<br> memset(readbuf, 0, bufferSize);<br> dataLen = read(*(int*)fd, readbuf, readbufLen);<br> }<br> delete []readbuf;<br>}<br>// 8. 启动线程读取管道数据并解析<br>pthread_t subTid = 0;<br>pthread_create(&subTid, NULL, profDataRead, &subFd[0]);<br>// 9.执行模型<br>ret = aclmdlExecute(modelId, input, output);<br>// 10.处理模型推理结果<br>// 11.释放描述模型输入/输出信息、内存等资源,卸载模型<br>// 12.取消订阅,释放订阅相关资源<br>aclprofModelUnSubscribe(modelId);<br>pthread_join(subTid, NULL);<br>// 关闭读管道指针<br>close(subFd[0]);<br>// 释放config指针<br>aclprofDestroySubscribeConfig(config);<br>// 13.释放运行管理资源<br>// 14. AscendCL去初始化<br>// ......<br> |
|---|
父主题: 扩展更多特性
溢出算子数据采集及分析
前提条件
使用ATC工具转换模型时,需在转换命令中增加--status_check参数,并将参数值设置为1,表示在编译算子时添加溢出检测逻辑。
关于ATC工具及其参数的详细说明,请参见《ATC工具使用指南》。
采集溢出算子信息
在调用aclInit接口初始化AscendCL时,在json配置文件中增加溢出算子Dump配置。
json配置文件中的示例内容如下,示例中的dump_path以相对路径为例:
{
"dump":{
"dump_path":"output",
"dump_debug":"on"
}
}
当dump_path配置为相对路径时,您可以在“应用可执行文件的目录/{dump_path}”下查看导出的数据文件,针对每个溢出算子,会导出两个数据文件:
-
溢出算子的dump文件:命名规则如{op_type}.{op_name}.{taskid}.{stream_id}.{timestamp},如果op_type、op_name出现了“.”、“/”、“\”、空格时,会转换为下划线表示。
用户可通过该信息知道具体出现溢出错误的算子,并通过解析溢出算子的dump文件获取该算子的输入和输出信息。
-
算子溢出数据文件:命名规则如OpDebug.Node_Opdebug.{taskid}.{stream_id}.{timestamp},其中taskid不是溢出算子的taskid,用户不需要关注taskid的实际含义。
用户可通过解析算子溢出数据文件获取溢出相关信息,包括溢出算子所在的模型、AICore的status寄存器状态等。
解析溢出算子的dump文件
-
请根据实际情况,将{op_type}.{op_name}.{taskid}.{stream_id}.{timestamp}上传到安装有Toolkit软件包的环境。
-
进入解析脚本所在目录,例如Toolkit软件包安装目录为:/home/HwHiAiUser/Ascend/ascend-toolkit/latest。
cd /home/HwHiAiUser/Ascend/ascend-toolkit/latest/toolkit/tools/operator_cmp/compare
-
执行msaccucmp.py脚本,转换dump文件为numpy文件。举例:
python3 msaccucmp.py convert -d /home/HwHiAiUser/dump -out /home/HwHiAiUser/dumptonumpy -v 2
:::note 说明 -d参数支持传入单个文件,对单个dump文件进行转换,也支持传入目录,对整个path下所有的dump文件进行转换。 :::
-
调用Python,转换numpy文件为txt文件。举例:
$ python3
>>> import numpy as np
>>> a = np.load("/home/HwHiAiUser/dumptonumpy/Pooling.pool1.1147.1589195081588018.output.0.npy")
>>> b = a.flatten()
>>> np.savetxt("/home/HwHiAiUser/dumptonumpy/Pooling.pool1.1147.1589195081588018.output.0.txt", b)
转换为.txt格式文件后,维度信息、Dtype均不存在。详细的使用方法请参考numpy官网介绍。
解析算子溢出数据文件
由于生成的溢出数据是二进制格式,可读性较差,需要通过工具将bin文件解析为用户可读性好的json文件。
-
请根据实际情况,将溢出数据文件OpDebug.Node_Opdebug.{taskid}.{timestamp}上传到安装有Toolkit软件包的环境。
-
进入解析脚本所在路径,例如Toolkit软件包安装目录为:/home/HwHiAiUser/Ascend/ascend-toolkit/latest。
cd /home/HwHiAiUser/Ascend/ascend-toolkit/latest/toolkit/tools/operator_cmp/compare
-
执行解析命令,例如:
python3 msaccucmp.py convert -d /home/HwHiAiUser**/opdebug/Opdebug.Node_OpDebug.59.1597922031178434** -out /home/HwHiAiUser/result
关键参数:
- -d:溢出数据文件所在目录,包括文件名。
- -out:解析结果待存储目录,如果不指定,默认生成在当前目录下。
-
解析结果文件内容如下所示。
{"DHA Atomic Add": {"model_id": 0,"stream_id": 0,"task_id": 0,"task_type": 0,"pc_start": "0x0","para_base": "0x0","status": 0},"L2 Atomic Add": {"model_id": 0,"stream_id": 0,"task_id": 0,"task_type": 0,"pc_start": "0x0","para_base": "0x0","status": 0},"AI Core": {"model_id": 514,"stream_id": 563,"task_id": 57,"task_type": 0,"pc_start": "0x1008005b0000","para_base": "0x100800297000","kernel_code": "0x1008005ae000","block_idx": 1,"status": 32}}参数解释:
-
model_id:标识溢出算子所在的模型id。
-
stream_id:标识溢出算子所在的streamid。
-
task_id:标识溢出算子的taskid。
-
task_type:标识溢出算子的task类型。
-
pc_start:标识溢出算子的代码程序的内存起始地址。
-
para_base:标识溢出算子的参数的内存起始地址。
-
kernel_code:标识溢出算子的代码程序的内存起始地址,和pc_start相同。
-
block_idx:标识溢出算子的blockid参数。
-
status:AICore的status寄存器状态,用户可以从status值分析得到具体溢出错误。status为10进制表示,需要转换成16进制,然后定位到具体错误。
例如:status为272,转换成16进制为0x00000110,则可以判定出可能原因为0x00000010+0x00000100。
- 0x00000008: 符号整数最小负数NEG符号位取反溢出
- 0x00000010: 整数加法、减法、乘法或乘加操作计算有溢出
- 0x00000020: 浮点计算有溢出
- 0x00000080: 浮点数转无符号数的输入是负数
- 0x00000100: FP32转FP16或32位符号整数转FP16中出现溢出
- 0x00000400: CUBE累加出现溢出
-
父主题: 扩展更多特性
在线提单