MI IPU API¶
REVISION HISTORY¶
| Revision No. | Description |
Date |
|---|---|---|
| 3.0 | 07/23/2021 | |
| 08/25/2021 | ||
| 11/30/2021 | ||
| 12/21/2021 | ||
| 01/20/2022 | ||
| 02/25/2022 | ||
| 06/01/2022 | ||
| 06/13/2022 | ||
| 08/15/2022 | ||
| 05/25/2023 | ||
| 09/26/2023 | ||
| 07/25/2024 | ||
| 04/16/2025 |
1. 概述¶
1.1. 模块说明¶
IPU是智能处理器,主要功能是在MI IPU模块驱动下实现AI模型的推演加速功能。
关键词说明:
-
IPU
智能处理器
-
Firmware
驱动IPU硬件的程序文件
-
Tensor
网络模型中的多维数据
-
Input Tensor
整个AI模型的输入Tensor
-
Output Tensor
整个AI 模型的输出Tensor
1.2. 基本结构¶
MI IPU具有多个channel,能够同时支持多个AI模型的推演。同时支持模块内部分配input/output tensor buffer,也支持直接使用前一级模块的output buffer 作为input tensor buffer。

从软件开发角度来看,应用程序通过MI IPU API调用IPU driver,进而通过IPU driver驱动IPU硬件,实现对AI模型的推理。

1.3. 功能介绍¶
MI IPU支持以下功能:
-
支持多线程、多进程执行模型推理
-
支持多通道
-
支持为模型自动分配buffer,同时也支持由用户来分配buffer
-
支持指定IPU推理任务的优先级
-
支持单次推理单张输入和单次推理多张输入
1.4. 应用场景¶
MI IPU具有以下应用场景:
- 机器人:应用于工业或服务机器人,实现环境感知、路径规划、任务执行等
- 智能IPC/NVR: 用于智能安防设备,结合人脸识别、行为分析、异常检测等功能,提升监控效果
- 会议系统:利用语音识别、人脸识别等技术优化会议体验
1.5. 芯片差异¶
本文档所描述芯片为Pcupid。各代芯片MI IPU模块的差异如下表所示。
| Pudding | Tiramisu | Muffin | Mochi | Maruko | Opera | Souffle | Ifado | Iford | Pcupid | Ibopper | Ifackel | Jaguar1 | Ifliegen | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Channel Number | 48 | 48 | 48 | 48 | 48 | 48 | 48 | 8 | 48 | 48 | 48 | 48 | 48 | 48 |
| Core Number | 1 | 1 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 2 |
注意:
- Ifackel与Ifliegen IPU的core0用于运行AI ISP模型,core1用于运行通用AI模型
- Muffin IPU的core0和core1都用于跑通用AI模型
1.6. 工作原理¶
用户在调用MI IPU模块进行模型推演前,首先需要使用IPU SDK工具链将原始的深度学习模型转换为硬件所支持的离线模型文件,然后通过调用MI IPU API在板端加载离线模型,并对离线模型推理进行加速。

1.7. 接口调用¶
当执行模型推理时,MI IPU的接口调用通常分为以下步骤:
-
解析模型信息,获取模型所需的variable buffer大小
-
创建IPU设备
-
创建IPU通道
-
获取IPU通道的输入、输出描述符
-
获取输入buffer的地址,并将输入内容拷贝到此buffer,然后flush cache,确保buffer与cache中内容相同
-
获取输出buffer的地址
-
执行模型推理
-
归还前述获取的输入、输出buffer到通道所有buffer
-
销毁IPU通道
-
销毁IPU设备

1.8. 实例介绍¶
1.8.1. dla_classify¶
dla_classify适用于推演分类模型,此时模型的输入格式要求为BGR或RGB。在运行时,该示例首先加载离线模型文件,并驱动IPU对输入图片进行分类,最后打印前5名的分类预测结果和对应的置信度。具体代码可参考
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <error.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <string>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <sys/time.h>
#include <unistd.h>
#include <sys/mman.h>
#if 0
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#endif
using namespace std;
using std::cout;
using std::endl;
using std::ostringstream;
using std::vector;
using std::string;
#include "mi_common_datatype.h"
#include "mi_sys_datatype.h"
#include "mi_ipu.h"
#include "mi_sys.h"
#define LABEL_IMAGE_FUNC_INFO(fmt, args...) do {printf("[Info ] [%-4d] [%10s] ", __LINE__, __func__); printf(fmt, ##args);} while(0)
#define alignment_up(a,b) (((a)+(b-1))&(~(b-1)))
struct PreProcessedData {
char *pImagePath;
int intResizeH;
int intResizeW;
int intResizeC;
bool bNorm;
float fmeanB;
float fmeanG;
float fmeanR;
float std;
bool bRGB;
unsigned char * pdata;
} ;
struct NetInfo {
MI_IPU_OfflineModelStaticInfo_t OfflineModelInfo;
MI_IPU_SubNet_InputOutputDesc_t desc;
};
#define LABEL_CLASS_COUNT (1200)
#define LABEL_NAME_MAX_SIZE (60)
MI_S32 IPUCreateDevice(char *pFirmwarePath,MI_U32 u32VarBufSize)
{
MI_S32 s32Ret = MI_SUCCESS;
MI_IPU_DevAttr_t stDevAttr;
memset(&stDevAttr, 0, sizeof(stDevAttr));
stDevAttr.u32MaxVariableBufSize = u32VarBufSize;
s32Ret = MI_IPU_CreateDevice(&stDevAttr, NULL, pFirmwarePath, 0);
return s32Ret;
}
static int H2SerializedReadFunc_1(void *dst_buf,int offset, int size, char *ctx)
{
// read data from buf
return 0;
}
static int H2SerializedReadFunc_2(void *dst_buf,int offset, int size, char *ctx)
{
// read data from buf
std::cout<<"read from call back function"<<std::endl;
memcpy(dst_buf,ctx+offset,size);
return 0;
}
MI_S32 IPUCreateChannel(MI_U32 *s32Channel, char *pModelImage)
{
MI_S32 s32Ret ;
MI_SYS_GlobalPrivPoolConfig_t stGlobalPrivPoolConf;
MI_IPUChnAttr_t stChnAttr;
//create channel
memset(&stChnAttr, 0, sizeof(stChnAttr));
stChnAttr.u32InputBufDepth = 2;
stChnAttr.u32OutputBufDepth = 2;
return MI_IPU_CreateCHN(s32Channel, &stChnAttr, NULL, pModelImage);
}
MI_S32 IPUCreateChannel_FromMemory(MI_U32 *s32Channel, char *pModelImage)
{
MI_S32 s32Ret ;
MI_SYS_GlobalPrivPoolConfig_t stGlobalPrivPoolConf;
MI_IPUChnAttr_t stChnAttr;
//create channel
memset(&stChnAttr, 0, sizeof(stChnAttr));
stChnAttr.u32InputBufDepth = 2;
stChnAttr.u32OutputBufDepth = 2;
return MI_IPU_CreateCHN(s32Channel, &stChnAttr, H2SerializedReadFunc_2, pModelImage);
}
MI_S32 IPUCreateChannel_FromEncryptFile(MI_U32 *s32Channel, char *pModelImage)
{
MI_S32 s32Ret ;
MI_SYS_GlobalPrivPoolConfig_t stGlobalPrivPoolConf;
MI_IPUChnAttr_t stChnAttr;
//create channel
memset(&stChnAttr, 0, sizeof(stChnAttr));
stChnAttr.u32InputBufDepth = 2;
stChnAttr.u32OutputBufDepth = 2;
return MI_IPU_CreateCHN(s32Channel, &stChnAttr, H2SerializedReadFunc_2, pModelImage);
}
MI_S32 IPUDestroyChannel(MI_U32 s32Channel)
{
MI_S32 s32Ret = MI_SUCCESS;
s32Ret = MI_IPU_DestroyCHN(s32Channel);
return s32Ret;
}
void GetImage( PreProcessedData *pstPreProcessedData)
{
string filename=(string)(pstPreProcessedData->pImagePath);
cv::Mat sample;
cv::Mat img = cv::imread(filename, -1);
if (img.empty()) {
std::cout << " error! image don't exist!" << std::endl;
exit(1);
}
int num_channels_ = pstPreProcessedData->intResizeC;
if (img.channels() == 3 && num_channels_ == 1)
{
cv::cvtColor(img, sample, cv::COLOR_BGR2GRAY);
}
else if (img.channels() == 4 && num_channels_ == 1)
{
cv::cvtColor(img, sample, cv::COLOR_BGRA2GRAY);
}
else if (img.channels() == 4 && num_channels_ == 3)
{
cv::cvtColor(img, sample, cv::COLOR_BGRA2BGR);
}
else if (img.channels() == 1 && num_channels_ == 3)
{
cv::cvtColor(img, sample, cv::COLOR_GRAY2BGR);
}
else
{
sample = img;
}
cv::Mat sample_float;
if (num_channels_ == 3)
sample.convertTo(sample_float, CV_32FC3);
else
sample.convertTo(sample_float, CV_32FC1);
cv::Mat sample_norm = sample_float;
if (pstPreProcessedData->bRGB)
{
cv::cvtColor(sample_float, sample_norm, cv::COLOR_BGR2RGB);
}
cv::Mat sample_resized;
cv::Size inputSize = cv::Size(pstPreProcessedData->intResizeW, pstPreProcessedData->intResizeH);
if (sample.size() != inputSize)
{
cout << "input size should be :" << pstPreProcessedData->intResizeC << " " << pstPreProcessedData->intResizeH << " " << pstPreProcessedData->intResizeW << endl;
cout << "now input size is :" << img.channels() << " " << img.rows<<" " << img.cols << endl;
cout << "img is going to resize!" << endl;
cv::resize(sample_norm, sample_resized, inputSize);
}
else
{
sample_resized = sample_norm;
}
float *pfSrc = (float *)sample_resized.data;
int imageSize = pstPreProcessedData->intResizeC*pstPreProcessedData->intResizeW*pstPreProcessedData->intResizeH;
for(int i=0;i<imageSize;i++)
{
*(pstPreProcessedData->pdata+i) = (unsigned char)(round(*(pfSrc + i)));
}
}
static MI_BOOL GetTopN(float aData[], int dataSize, int aResult[], int TopN)
{
int i, j, k;
float data = 0;
MI_BOOL bSkip = FALSE;
for (i=0; i < TopN; i++)
{
data = -0.1f;
for (j = 0; j < dataSize; j++)
{
if (aData[j] > data)
{
bSkip = FALSE;
for (k = 0; k < i; k++)
{
if (aResult[k] == j)
{
bSkip = TRUE;
}
}
if (bSkip == FALSE)
{
aResult[i] = j;
data = aData[j];
}
}
}
}
return TRUE;
}
MI_U32 _MI_IPU_GetTensorUnitDataSize(MI_IPU_ELEMENT_FORMAT eElmFormat)
{
switch (eElmFormat) {
case MI_IPU_FORMAT_INT16:
return sizeof(short);
case MI_IPU_FORMAT_INT32:
return sizeof(int);
case MI_IPU_FORMAT_INT8:
return sizeof(char);
case MI_IPU_FORMAT_FP32:
return sizeof(float);
case MI_IPU_FORMAT_UNKNOWN:
default:
return 1;
}
}
MI_U32 IPU_CalcTensorSize(MI_IPU_TensorDesc_t* pstTensorDescs)
{
MI_U32 u32Size = 1;
MI_U32 u32UnitSize = 1;
u32UnitSize = _MI_IPU_GetTensorUnitDataSize(pstTensorDescs->eElmFormat);
for (int i = 0; i < pstTensorDescs->u32TensorDim; i++)
{
u32Size *= pstTensorDescs->u32TensorShape[i];
}
u32Size *= u32UnitSize;
return u32Size;
}
static void IPU_PrintOutputXOR(MI_IPU_SubNet_InputOutputDesc_t* desc, MI_IPU_TensorVector_t OutputTensorVector)
{
MI_U32 u32InputNum = desc->u32InputTensorCount;
MI_U32 u32OutputNum = desc->u32OutputTensorCount;
volatile MI_U32 u32XORValue = 0;
MI_U8 *pu8XORValue[4]= {(MI_U8 *)&u32XORValue,(MI_U8 *)&u32XORValue+1,(MI_U8 *)&u32XORValue+2,(MI_U8 *)&u32XORValue+3 };
MI_U32 u32Count = 0;
for (MI_U32 idxOutputNum = 0; idxOutputNum < desc->u32OutputTensorCount; idxOutputNum++)
{
MI_U8 u8Data = 0;
MI_U8 *pu8Data = (MI_U8 *)OutputTensorVector.astArrayTensors[idxOutputNum].ptTensorData[0];
for(int i = 0; i < IPU_CalcTensorSize(&(desc->astMI_OutputTensorDescs[idxOutputNum])); i++)
{
u8Data = *(pu8Data + i);
*pu8XORValue[u32Count%4] ^= u8Data;
u32Count++;
}
}
printf("All outputs XOR = 0x%08x\n", u32XORValue);
}
int main(int argc,char *argv[])
{
if ( argc < 5 )
{
std::cout << "USAGE: " << argv[0] <<": <xxxsgsimg.img> " \
<< "<picture> " << "<labels> "<< "<model intput_format:RGB or BGR>"<<std::endl;
exit(0);
} else {
std::cout<<"model_img:"<<argv[1]<<std::endl;
std::cout<<"picture:"<<argv[2]<<std::endl;
std::cout<<"labels:"<<argv[3]<<std::endl;
std::cout<<"model input_format:"<<argv[4]<<std::endl;
}
char * pFirmwarePath = NULL;
char * pModelImgPath = argv[1];
char * pImagePath= argv[2];
char * pLabelPath =argv[3];
char * pRGB = argv[4];
char * pfps = NULL;
char * ptime = NULL;
int fps = -1;
int duration = -1;
if (argc == 7)
{
pfps = argv[5];
ptime = argv[6];
fps = atoi(pfps);
duration = atoi(ptime);
}
MI_BOOL bRGB = FALSE;
if(strncmp(pRGB,"RGB",sizeof("RGB"))!=0 && strncmp(pRGB,"BGR",sizeof("BGR"))!=0 && strncmp(pRGB,"RAWDATA",sizeof("RAWDATA"))!=0)
{
std::cout << "model intput_format error" <<std::endl;
return -1;
}
static char label[LABEL_CLASS_COUNT][LABEL_NAME_MAX_SIZE];
MI_U32 u32ChannelID = 0;
MI_S32 s32Ret;
MI_IPU_TensorVector_t InputTensorVector;
MI_IPU_TensorVector_t OutputTensorVector;
auto net_info = std::make_shared<NetInfo>();
ifstream LabelFile;
LabelFile.open(pLabelPath);
int n=0;
while(1)
{
LabelFile.getline(&label[n][0],60);
if(LabelFile.eof())
break;
n++;
if(n>=LABEL_CLASS_COUNT)
{
cout<<"the labels have line:"<<n<<" ,it supass the available label array"<<std::endl;
break;
}
}
LabelFile.close();
MI_SYS_Init(0);
//1.create device
cout<<"get variable size from memory__"<<std::endl;
char *pmem = NULL;
int fd = 0;
struct stat sb;
fd = open(pModelImgPath, O_RDWR);
if (fd < 0)
{
perror("open");
return -1;
}
memset(&sb, 0, sizeof(sb));
if (fstat(fd, &sb) < 0)
{
perror("fstat");
return -1;
}
pmem = (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (pmem == NULL)
{
perror("mmap");
return -1;
}
if (MI_SUCCESS != MI_IPU_GetOfflineModeStaticInfo(H2SerializedReadFunc_2, pmem, &net_info->OfflineModelInfo))
{
cout<<"get model variable buffer size failed!"<<std::endl;
return -1;
}
if(MI_SUCCESS !=IPUCreateDevice(pFirmwarePath,net_info->OfflineModelInfo.u32VariableBufferSize))
{
cout<<"create ipu device failed!"<<std::endl;
return -1;
}
//2.create channel
/*case 0 create module from path*/
#if 0
if(MI_SUCCESS !=IPUCreateChannel(u32ChannelID,pModelImgPath))
{
cout<<"create ipu channel failed!"<<std::endl;
MI_IPU_DestroyDevice();
return -1;
}
#endif
#if 1
/*case1 create channel from memory*/
cout<<"create channel from memory__"<<std::endl;
if(MI_SUCCESS !=IPUCreateChannel_FromMemory(&u32ChannelID,pmem))
{
cout<<"create ipu channel failed!"<<std::endl;
MI_IPU_DestroyDevice();
return -1;
}
#endif
//3.get input/output tensor
s32Ret = MI_IPU_GetInOutTensorDesc(u32ChannelID, &net_info->desc);
if (s32Ret == MI_SUCCESS) {
for (int i = 0; i < net_info->desc.u32InputTensorCount; i++) {
cout<<"input tensor["<<i<<"] name :"<<net_info->desc.astMI_InputTensorDescs[i].name<<endl;
}
for (int i = 0; i < net_info->desc.u32OutputTensorCount; i++) {
cout<<"output tensor["<<i<<"] name :"<<net_info->desc.astMI_OutputTensorDescs[i].name<<endl;
}
}
unsigned char *pu8ImageData = NULL;
const char* dump_input_bin = getenv("DUMP_INPUT_BIN");
MI_IPU_GetInputTensors( u32ChannelID, &InputTensorVector);
int datasize = 0;
if(strncmp(pRGB,"RAWDATA",sizeof("RAWDATA"))==0)
{
FILE* stream;
stream = fopen(pImagePath,"r");
fseek(stream, 0, SEEK_END);
int length = ftell(stream);
cout << "length==" << length<<endl;
rewind(stream);
if(length != net_info->desc.astMI_InputTensorDescs[0].s32AlignedBufSize)
{
cout<<"please check input bin size"<<endl;
exit(0);
}
pu8ImageData = new unsigned char[length];
datasize = fread(pu8ImageData,sizeof(unsigned char),length,stream);
cout << "size==" << datasize <<endl;
fclose(stream);
}
else
{
int intResizeH = net_info->desc.astMI_InputTensorDescs[0].u32TensorShape[1];
int intResizeW = net_info->desc.astMI_InputTensorDescs[0].u32TensorShape[2];
int intResizeC = net_info->desc.astMI_InputTensorDescs[0].u32TensorShape[3];
pu8ImageData = new unsigned char[intResizeH*intResizeW*intResizeC];
PreProcessedData stProcessedData;
stProcessedData.intResizeC = intResizeC;
stProcessedData.intResizeH = intResizeH;
stProcessedData.intResizeW = intResizeW;
stProcessedData.pdata = pu8ImageData;
stProcessedData.pImagePath = pImagePath;
if(strncmp(pRGB,"RGB",sizeof("RGB"))==0)
{
bRGB = TRUE;
}
stProcessedData.bRGB = bRGB;
GetImage(&stProcessedData);
datasize=intResizeH*intResizeW*intResizeC;
}
memcpy(InputTensorVector.astArrayTensors[0].ptTensorData[0],pu8ImageData,datasize);
MI_SYS_FlushInvCache(InputTensorVector.astArrayTensors[0].ptTensorData[0], datasize);
MI_IPU_GetOutputTensors( u32ChannelID, &OutputTensorVector);
if(dump_input_bin)
{
FILE* stream_input = fopen("inputtoinvoke.bin","w");
int input_size = fwrite(InputTensorVector.astArrayTensors[0].ptTensorData[0],sizeof(unsigned char),datasize,stream_input);
fclose(stream_input);
}
//4.invoke
int times = 32;
if(fps!=-1)
{
times =duration*fps;
}
printf("the times is %d \n",times);
struct timespec ts_start, ts_end;
clock_gettime(CLOCK_MONOTONIC, &ts_start);
for (int i=0;i<times;i++ )
{
struct timespec ts_start_1;
clock_gettime(CLOCK_MONOTONIC, &ts_start_1);
if(MI_SUCCESS!=MI_IPU_Invoke(u32ChannelID, &InputTensorVector, &OutputTensorVector))
{
cout<<"IPU invoke failed!!"<<endl;
delete pu8ImageData;
IPUDestroyChannel(u32ChannelID);
MI_IPU_DestroyDevice();
return -1;
}
struct timespec ts_end_1;
clock_gettime(CLOCK_MONOTONIC, &ts_end_1);
int elasped_time_1 = (ts_end_1.tv_sec-ts_start_1.tv_sec)*1000000+(ts_end_1.tv_nsec-ts_start_1.tv_nsec)/1000;
float durationInus = 0.0;
if(fps!=-1)
{
durationInus = 1000000.0/fps;
}
if ((elasped_time_1<durationInus)&&(fps!=-1))
{
usleep((int)(durationInus-elasped_time_1));
}
}
clock_gettime(CLOCK_MONOTONIC, &ts_end);
int elasped_time = (ts_end.tv_sec-ts_start.tv_sec)*1000000+(ts_end.tv_nsec-ts_start.tv_nsec)/1000;
cout<<"fps:"<<1000.0/(float(elasped_time)/1000/times)<<std::endl;
// show result of classify
IPU_PrintOutputXOR(&net_info->desc, OutputTensorVector);
int s32TopN[5];
memset(s32TopN,0,sizeof(s32TopN));
int iDimCount = net_info->desc.astMI_OutputTensorDescs[0].u32TensorDim;
int s32ClassCount = 1;
for(int i=0;i<iDimCount;i++ )
{
s32ClassCount *= net_info->desc.astMI_OutputTensorDescs[0].u32TensorShape[i];
}
float *pfData = (float *)OutputTensorVector.astArrayTensors[0].ptTensorData[0];
cout<<"the class Count :"<<s32ClassCount<<std::endl;
cout<<std::endl;
cout<<std::endl;
GetTopN(pfData, s32ClassCount, s32TopN, 5);
for(int i=0;i<5;i++)
{
cout<<"order: "<<i+1<<" index: "<<s32TopN[i]<<" "<<pfData[s32TopN[i]]<<" "<<label[s32TopN[i]]<<endl;
}
//5. put intput tensor
MI_IPU_PutInputTensors(u32ChannelID,&InputTensorVector);
MI_IPU_PutOutputTensors(u32ChannelID,&OutputTensorVector);
//6.destroy channel/device
delete pu8ImageData;
IPUDestroyChannel(u32ChannelID);
MI_IPU_DestroyDevice();
return 0;
}
1.8.2. dla_detect¶
dla_detect用于推演检测模型,且检测模型的输入格式需要为RGB或BGR,模型必须使用SGS的后处理方法。在运行时,该示例首先加载离线模型文件,并驱动IPU对输入图片进行推理检测,最后在当前目录下输出带有检测结果框的图片。具体代码可参考
1.8.3. dla_classifyNBatch¶
dla_classifyNBatch同样用于推演分类模型,对于模型及输入的要求与dla_classify相同。不同之处在于,该示例展示了调用MI_IPU_Invoke2和MI_IPU_Invoke2Custom时输入、输出内存的排布方式,和用户自己分配内存时需要调用的接口和内存对齐等注意事项。具体代码可参考
1.8.4. dla_simulator¶
dla_simulator用于在板端推理模型,并与PC端IPU SDK工具链提供的simulator.py的运行结果进行比对,从而在板端验证模型推理的正确性。该示例适用的模型为经IPU SDK工具链转换的离线模型,模型输入及格式由模型自身决定。具体代码可参考
1.8.5. dla_simulatorNBatch¶
dla_simulatorNBatch同样用于推理板端模型,其适用模型和输入要求同dla_simulator。不同之处在于,dla_simulatorNBatch示例中调用MI_IPU_Invoke2接口,支持单次推理多张输入。具体代码可参考
1.8.6. dla_show_img_info¶
dla_show_img_info用于展示板端推理离线模型的帧率和带宽统计数据,还可以抓取IPU log来分析模型每层性能。其输入为经过IPU SDK工具链转换的任意模型。具体代码可参考
1.8.7. ipu_log¶
ipu_log工具用于在需要分析模型每层性能时抓取IPU log。该工具也集成在dla_show_img_info中。IPU log的开启方法参考抓取IPU log。具体代码可参考
1.8.8. ipu_utilization¶
ipu_utilization用于打印IPU的使用率。当应用程序调用MI IPU接口推理模型时,可运行该工具查看IPU的使用率情况。具体代码可参考
1.8.9. ipu_server¶
ipu_server用于创建IPU的推理服务,在PC端使用python接口推理模型。首先在板端运行该工具并配置端口号,然后在PC端使用IPU SDK工具链提供的rpc_simulator.py连接板端IP和配置的端口号。该工具可推理任意模型,运行结果保存在PC端当前目录下的log/output里。更多rpc_simulator的使用可参考IPU SDK用户文档。具体代码可参考
2. API参考¶
2.1. 功能模块API¶
| API名 | 功能 |
|---|---|
| MI_IPU_CreateDevice | 创建IPU设备 |
| MI_IPU_DestroyDevice | 销毁IPU设备 |
| MI_IPU_CreateCHN | 创建IPU通道 |
| MI_IPU_DestroyCHN | 销毁指定IPU通道 |
| MI_IPU_GetInOutTensorDesc | 获取指定通道的网络模型输入输出信息 |
| MI_IPU_GetInputTensors | 从指定通道分配输入Tensor Buffer |
| MI_IPU_PutInputTensors | 释放指定通道的输入Tensor Buffer |
| MI_IPU_GetOutputTensors | 从指定通道分配输出Tensor Buffer |
| MI_IPU_PutOutputTensors | 释放指定通道的输出Tensor Buffer |
| MI_IPU_Invoke | 执行一次网络模型推演 |
| MI_IPU_GetInputTensors2 | 从指定通道分配批处理输入Tensor Buffer |
| MI_IPU_PutInputTensors2 | 释放指定通道的批处理输入Tensor Buffer |
| MI_IPU_GetOutputTensors2 | 从指定通道分配批处理输出Tensor Buffer |
| MI_IPU_PutOutputTensors2 | 释放指定通道的批处理输出Tensor Buffer |
| MI_IPU_Invoke2 | 执行一次n_buf batch模式网络模型推演 |
| MI_IPU_Invoke2Custom | 执行一次one_buf batch模式网络模型推演 |
| MI_IPU_GetOfflineModeStaticInfo | 获取离线模型运行需要的variable buffer size和离线模型文件大小 |
| MI_IPU_CancelInvoke | 取消正在执行的Invoke任务 |
| MI_IPU_CreateCHNWithUserMem | 使用用户提供的MMA内存创建IPU通道 |
| MI_IPU_DestroyDeviceExt | 使用参数销毁IPU设备 |
2.2. MI_IPU_CreateDevice¶
-
功能
创建IPU设备。
-
语法
MI_S32 MI_IPU_CreateDevice(MI_IPU_DevAttr_t *pstIPUDevAttr, SerializedReadFunc pReadFunc, char *pReadCtx, MI_U32 FWSize); -
形参
参数名称 描述 输入/输出 pstIPUDevAttr IPU设备属性结构体指针 输入 pReadFunc 用户自定义读取文件函数指针(设为NULL默认使用MI IPU提供的文件读取函数) 输入 pReadCtx IPU firmware文件路径(设为NULL默认使用MI IPU提供的文件路径:/config/dla/ipu_firmware.bin) 输入 FWSize IPU firmware文件大小(设为0默认MI IPU自动获取文件大小) 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
举例
MI_S32 s32Ret; stDevAttr.u32MaxVariableBufSize = BufSize; /*模型内部Tensor使用的memory的最大size*/ s32Ret = MI_IPU_CreateDevice(&stDevAttr, NULL, NULL, 0); if (s32Ret != MI_SUCCESS) { printf("fail to create ipu device\n"); return s32Ret; }
2.3. MI_IPU_DestroyDevice¶
-
功能
销毁IPU设备。
-
语法
MI_S32 MI_IPU_DestroyDevice(void); -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_DestroyDevice();
2.4. MI_IPU_CreateCHN¶
-
功能
创建IPU通道。
-
语法
MI_S32 MI_IPU_CreateCHN(MI_IPU_CHN *ptChnId,MI_IPUChnAttr_t *pstIPUChnAttr, SerializedReadFunc pReadFunc, char *pReadCtx); -
参数
参数名称 描述 输入/输出 ptChnId 获取IPU通道ID的指针 输出 pstIPUChnAttr IPU通道描述信息结构体指针 输入 pReadFunc 用户自定义读取文件函数(设为NULL默认使用MI IPU提供的文件读取函数) 输入 pReadCtx 网络模型文件路径或者网络模型OS内存地址 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
-
MI_IPUChnAttr_t.u32BatchMax 为批处理的最大值,如果这个模型不需要使用批处理,则将该值设置为1或者0。
-
MI_IPUChnAttr_t.u32InputBufDepth 为设定的输入预分配私有tensor buffer* u32BatchMax的个数,比如 0 or 1 or 2 or 3, 当设置为0时,表示buffer来源于外部。如果直接使用前级模块的输出MI buffer,建议此处设置input_depth为0避免内存浪费。
-
MI_IPUChnAttr_t. u32OutputBufDepth为设定的输出预分配私有tensor buffer* u32BatchMax的个数, 比如 0 or 1 or 2 or 3,当设置为0时,表示buffer来源于外部,如MI_RGN模块。
-
如果创建的是one_buf batch模式网络模型,则不会预分配输入和输出buffer。
-
IPU最大通道数为48。
-
-
举例
MI_S32 s32Ret, buf_depth = 3, batch_max = 1; MI_IPU_CHN u32ChnId = 0; chnAttr.u32InputBufDepth = buf_depth; chnAttr.u32OutputBufDepth = buf_depth; chnAttr.u32BatchMax = batch_max; char pReadCtx[] = "caffe_mobilenet_v2.tflite_sgsimg.img"; s32Ret = MI_IPU_CreateCHN(&u32ChnId, &chnAttr, NULL, pReadCtx); if (s32Ret != MI_SUCCESS) { printf("fail to create ipu channel\n"); return s32Ret; }
2.5. MI_IPU_DestroyCHN¶
-
功能
销毁指定IPU通道。
-
语法
MI_S32 MI_IPU_DestroyCHN(MI_IPU_CHN u32ChnId); -
参数
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
- IPU最大通道数为48。
-
举例
MI_IPU_DestroyCHN(u32ChnId);
2.6. MI_IPU_GetInOutTensorDesc¶
-
描述
获取指定通道的网络模型输入输出信息。
-
语法
MI_S32 MI_IPU_GetInOutTensorDesc(MI_IPU_CHN u32ChnId,MI_IPU_SubNet_InputOutputDesc_t *pstDesc); -
参数
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstDesc 网络描述结构体指针 输出 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
- IPU最大通道数为48。
-
举例
MI_IPU_SubNet_InputOutputDesc_t desc; s32Ret = MI_IPU_GetInOutTensorDesc(u32ChnId, &desc); if (s32Ret) { printf("fail to get network description\n"); MI_IPU_DestroyCHN(u32ChnId); MI_IPU_DestroyDevice(); return s32Ret; } else { int iNum = desc.astMI_InputTensorDescs[0].u32TensorShape[0]; int iResizeH = desc.astMI_InputTensorDescs[0].u32TensorShape[1]; int iResizeW = desc.astMI_InputTensorDescs[0].u32TensorShape[2]; int iResizeC = desc.astMI_InputTensorDescs[0].u32TensorShape[3]; unsigned char *pu8ImageData = new unsigned char[iNum*iResizeH*iResizeW*iResizeC]; ... }
2.7. MI_IPU_GetInputTensors¶
-
描述
从指定通道获取输入Tensor Buffer。
-
语法
MI_S32 MI_IPU_GetInputTensors(MI_IPU_CHN u32ChnId,MI_IPU_TensorVector_t *pstInputTensorVector); -
参数
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInputTensorVector 输入IPU Tensor数组结构体指针 输出 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
-
输入Tensor的Buffer来源有2种方式:
-
通过MI_IPU_GetInputTensors分配Buffer;
-
使用MI的其他模块已分配的Buffer。
-
-
-
举例
通过MI_IPU_GetInputTensors分配buffer:
MI_IPU_TensorVector_t inputV; MI_IPU_TensorVector_t OutputV; MI_U8 au8MaggiePic[3*224*224] ; cv::Mat img = cv::imread(filename, -1); cv::Size inputSize = cv::Size(224,224,3) cv ::Mat imgResize ; cv::resize(img, imgResize, inputSize); memcpy(au8MaggiePic, imgResize.data, sizeof(au8MaggiePic)); s32Ret = MI_IPU_GetInputTensors(u32ChnId, &inputV); if (s32Ret == MI_SUCCESS) { memcpy(inputV.astArrayTensors[0].ptTensorData[0], au8MaggiePic, sizeof(au8MaggiePic)); MI_SYS_FlushInvCache(inputV.astArrayTensors[0].ptTensorData[0], sizeof(au8MaggiePic)); } else { printf(“fail to get buffer, please try again”); } MI_IPU_GetOutputTensors( u32ChannelID, &OutputV); if(MI_SUCCESS!=MI_IPU_Invoke(u32ChannelID, & inputV, &OutputV)) { cout<<"IPU invoke failed!!"<<endl; MI_IPU_DestroyCHN(u32ChannelID); MI_IPU_DestroyDevice(); return -1; }使用MI其他模块已经分配的buffer
MI_IPU_TensorVector_t inputVector, outputVector; inputVector.u32TensorCount = 1; if (stBufInfo.eBufType == E_MI_SYS_BUFDATA_RAW) { inputVector.astArrayTensors[0].phyTensorAddr[0] = stBufInfo.stRawData.phyAddr; inputVector.astArrayTensors[0].ptTensorData[0] = stBufInfo.stRawData.pVirAddr; } else if (stBufInfo.eBufType == E_MI_SYS_BUFDATA_FRAME) { inputVector.astArrayTensors[0].phyTensorAddr[0] = stBufInfo.stFrameData.phyAddr[0]; inputVector.astArrayTensors[0].ptTensorData[0] = stBufInfo.stFrameData.pVirAddr[0]; inputVector.astArrayTensors[0].phyTensorAddr[1] = stBufInfo.stFrameData.phyAddr[1]; inputVector.astArrayTensors[0].ptTensorData[1] = stBufInfo.stFrameData.pVirAddr[1]; } //prepare output vector s32Ret = MI_IPU_GetOutputTensors(FdaChn, &outputVector); s32Ret = MI_IPU_Invoke(FdaChn, &inputVector, &outputVector);
2.8. MI_IPU_PutInputTensors¶
-
功能
释放指定通道的输入Tensor Buffer。
-
语法
MI_S32 MI_IPU_PutInputTensors(MI_IPU_CHN u32ChnId,MI_IPU_TensorVector_t *pstInputTensorVector); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道号 输入 pstInputTensorVector 输入IPU Tensor数组结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
2.9. MI_IPU_GetOutputTensors¶
-
功能
从指定通道获取输出Tensor Buffer。
-
语法
MI_S32 MI_IPU_GetOutputTensors(MI_IPU_CHN u32ChnId,MI_IPU_TensorVector_t *pstInputTensorVector); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInputTensorVector 输出IPU Tensor数组结构体指针 输出 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_TensorVector_t outputV; s32Ret = MI_IPU_GetOutputTensors(u32ChnId, &outputV); if (s32Ret != MI_SUCCESS) { printf(“fail to get buffer, please try again”); }
2.10. MI_IPU_PutOutputTensors¶
-
功能
释放指定通道的输出Tensor Buffer。
-
语法
MI_S32 MI_IPU_PutOutputTensors(MI_IPU_CHN u32ChnId,MI_IPU_TensorVector_t *pstInputTensorVector); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInputTensorVector 输出IPU Tensor数组结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
2.11. MI_IPU_Invoke¶
-
功能
执行一次AI网络推演过程。
-
语法
MI_S32 MI_IPU_Invoke(MI_IPU_CHN u32ChnId,MI_IPU_TensorVector_t *pstInputTensorVector,MI_IPU_TensorVector_t *pstOuputTensorVector); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInputTensorVector 输入IPU Tensor数组结构体指针 输入 pstOuputTensorVector 输出IPU Tensor数组结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
-
MI_IPU_Invoke为同步API。
-
每一个输入/输出tensor的起始物理地址必须64 bytes 对齐。
-
-
举例
s32Ret =MI_IPU_Invoke(u32ChnId, &inputV, &outputV); if (s32Ret == MI_SUCCESS) { // process output buffer data // ... }
2.12. MI_IPU_GetInputTensors2¶
-
功能
从指定通道获取批处理输入Tensor Buffer
-
语法
MI_S32 MI_IPU_GetInputTensors2(MI_IPU_CHN u32ChnId, MI_IPU_BatchInvoke_param_t *pstInvokeParam); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInvokeParam 批处理参数结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
输入Tensor的Buffer来源有2种方式:
-
通过MI_IPU_GetInputTensors2分配Buffer;
-
使用MI的其他模块已分配的Buffer。
-
2.13. MI_IPU_PutInputTensors2¶
-
功能
释放指定通道的批处理输入Tensor Buffer。
-
语法
MI_S32 MI_IPU_PutInputTensors2(MI_IPU_CHN u32ChnId, MI_IPU_BatchInvoke_param_t *pstInvokeParam); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInvokeParam 批处理参数结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
2.14. MI_IPU_GetOutputTensors2¶
-
功能
从指定通道获取批处理输出Tensor Buffer。
-
语法
MI_S32 MI_IPU_GetOutputTensors2(MI_IPU_CHN u32ChnId, MI_IPU_BatchInvoke_param_t *pstInvokeParam); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInvokeParam 批处理参数结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
2.15. MI_IPU_PutOutputTensors2¶
-
功能
释放指定通道的批处理输出Tensor Buffer。
-
语法
MI_S32 MI_IPU_PutOutputTensors2(MI_IPU_CHN u32ChnId, MI_IPU_BatchInvoke_param_t *pstInvokeParam); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInvokeParam 批处理参数结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
2.16. MI_IPU_Invoke2¶
-
功能
执行一次n_buf batch模式网络模型推演。
-
语法
MI_S32 MI_IPU_Invoke2(MI_IPU_CHN u32ChnId, MI_IPU_BatchInvoke_param_t *pstInvokeParam, MI_IPU_RuntimeInfo_t *pstRuntimeInfo); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInvokeParam 批处理参数结构体指针 输入 pstRuntimeInfo IPU运行信息结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
-
MI_IPU_Invoke2为同步API。
-
MI_IPU_Invoke2只能推理n_buf batch模式的模型。
-
每一个输入/输出tensor的起始物理地址必须64 bytes 对齐。
-
用户指定的variable buffer的起始物理地址必须64 bytes 对齐。
-
-
举例
MI_IPU_BatchInvoke_param_t stInvokeParam; MI_IPU_RuntimeInfo_t stRuntimeInfo; stInvokeParam.u32BatchN = 16; stInvokeParam.s32TaskPrio = 20; stInvokeParam.u32IpuAffinity = 0; //由ipu调度 s32Ret = MI_IPU_GetInputTensors2(u32ChnId, &stInvokeParam); if (s32Ret != MI_SUCCESS) { printf(“Error: MI_IPU_GetInputTensors2 return %d\n”, s32Ret); return -1; } s32Ret = MI_IPU_GetOutputTensors2(u32ChnId, &stInvokeParam); if (s32Ret != MI_SUCCESS) { printf(“Error: MI_IPU_ GetOutputTensors2 return %d\n”, s32Ret); MI_IPU_PutInputTensors2(u32ChnId, &stInvokeParam); return -1; } s32Ret = MI_IPU_Invoke2(u32ChnId, &stInvokeParam, &stRuntimeInfo); if (s32Ret == MI_SUCCESS) { // process output buffer data // ... printf(“bw_total=%llu, bw_read=%llu, bw_read=%llu, iputime=%llu\n”, stRuntimeInfo.u64BandWidth, stRuntimeInfo.u64BandWidthRead, stRuntimeInfo.u64BandWidthWrite, stRuntimeInfo.u64IpuTime); }
2.17. MI_IPU_Invoke2Custom¶
-
功能
执行一次one_buf batch模式网络模型推演。
-
语法
MI_S32 MI_IPU_Invoke2Custom(MI_IPU_CHN u32ChnId, MI_IPU_BatchInvoke_param_t *pstInvokeParam, MI_IPU_RuntimeInfo_t *pstRuntimeInfo); -
形参
参数名称 描述 输入/输出 u32ChnId IPU通道ID 输入 pstInvokeParam 批处理参数结构体指针 输入 pstRuntimeInfo IPU运行信息结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
-
MI_IPU_Invoke2Custom为同步API。
-
MI_IPU_Invoke2Custom只能推理one_buf batch模式模型。
-
每一个输入/输出tensor的起始物理地址必须64 bytes 对齐。
-
用户指定的variable buffer的起始物理地址必须64 bytes 对齐。
-
-
举例
// input tensor number=1 output tensor number=1 MI_IPU_BatchInvoke_param_t stInvokeParam; MI_IPU_RuntimeInfo_t stRuntimeInfo; stInvokeParam.u32BatchN = 10; stInvokeParam.s32TaskPrio = 20; stInvokeParam.u32IpuAffinity = 0; //由ipu调度 int s32InputSize, s32InputSizeOne; s32InputSizeOne = stDesc.astMI_InputTensorDescs[0].u32BufSize; s32InputSize = s32InputSizeOne * stInvokeParam.u32BatchN; int s32OutputSize, s32OutputSizeOne; s32OutputSizeOne = stDesc.astMI_OutputTensorDescs[0].u32BufSize; s32OutputSize = s32OutputSizeOne * stInvokeParam.u32BatchN; s32Ret = MI_SYS_MMA_Alloc(0, NULL, s32InputSize, &u64InputPhyAddr); if (s32Ret != MI_SUCCESS) { printf("fail to allocate input buffer\n"); return -1; } s32Ret = MI_SYS_Mmap(u64InputPhyAddr, s32InputSize, &pInputVirAddr, TRUE); if (s32Ret != MI_SUCCESS) { MI_SYS_MMA_Free(0, u64InputPhyAddr); printf("Error: fail to map input address, error=%d\n", s32Ret); return -1; } stInvokeParam.astArrayTensors[0].ptTensorData[0] = pInputVirAddr; stInvokeParam.astArrayTensors[0].phyTensorAddr[0] = u64InputPhyAddr; s32Ret = MI_SYS_MMA_Alloc(0, NULL, s32OutputSize, &u64OutputPhyAddr); if (s32Ret != MI_SUCCESS) { MI_SYS_Munmap(pInputVirAddr, s32InputSize); MI_SYS_MMA_Free(0, u64InputPhyAddr); printf("fail to allocate output buffer\n"); return -1; } s32Ret = MI_SYS_Mmap(u64OutputPhyAddr, s32OutputSize, &pOutputVirAddr, TRUE); if (s32Ret != MI_SUCCESS) { MI_SYS_Munmap(pInputVirAddr, s32InputSize); MI_SYS_MMA_Free(0, u64InputPhyAddr); MI_SYS_MMA_Free(0, u64OutputPhyAddr); printf("Error: fail to map output address, error=%d\n", s32Ret); return -1; } stInvokeParam.astArrayTensors[1].ptTensorData[0] = pOutputVirAddr; stInvokeParam.astArrayTensors[1].phyTensorAddr[0] = u64OutputPhyAddr; for (int i = 0; i < stInvokeParam.u32BatchN; i++) { memcpy(pInputVirAddr+i*s32InputSizeOne; pInputBuf[i], s32InputSizeOne); } MI_SYS_FlushInvCache(pInputVirAddr, s32InputSize); s32Ret = MI_IPU_Invoke2Custom(channel, &stInvokeParam, NULL); if (s32Ret != MI_SUCCESS) { printf("fail to invoke\n"); MI_SYS_Munmap(pInputVirAddr, s32InputSize); MI_SYS_MMA_Free(0, u64InputPhyAddr); MI_SYS_Munmap(pOutputVirAddr, s32OutputSize); MI_SYS_MMA_Free(0, u64OutputPhyAddr); return -1; } else { // process output data for (int i = 0; i < stInvokeParam.u32BatchN; i++) { // pOutputVirAddr+i*s32OutputSizeOne } }
2.18. MI_IPU_GetOfflineModeStaticInfo¶
-
功能
获取离线模型运行需要的variable buffer size和离线模型文件大小
-
语法
MI_S32 MI_IPU_GetOfflineModeStaticInfo(SerializedReadFunc pReadFunc, char *pReadCtx, MI_IPU_OfflineModelStaticInfo_t *pStaticInfo); -
形参
参数名称 描述 输入/输出 pReadFunc 用户自定义读取文件函数(设为NULL默认使用MI IPU提供的文件读取函数 输入 pReadCtx 离线模型文件路径 输入 pStaticInfo 离线模型静态信息结构体指针 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
举例
MI_IPU_OfflineModelStaticInfo_t staticInfo; s32Ret = MI_IPU_GetOfflineModeStaticInfo(NULL, pModelImgPath, &staticInfo); if (s32Ret == MI_SUCCESS) { printf("variable buffer size: %u bytes\n%s size: %u bytes\n", staticInfo.u32VariableBufferSize, pModelImgPath, staticInfo.u32OfflineModelSize); }
2.19. MI_IPU_CancelInvoke¶
-
功能
取消正在执行的Invoke任务
-
语法
MI_S32 MI_IPU_CancelInvoke(MI_U32 u32ThreadId, MI_IPU_CHN u32ChnId); -
形参
参数名称 描述 输入/输出 u32ThreadId 指定取消的invoke任务所属的线程ID 输入 u32ChnId 指定取消的invoke任务所属的通道ID 输入 -
返回值
- MI_SUCCESS成功。
- 非MI_SUCCESS失败,参照错误码。
-
依赖
- 头文件:mi_ipu.h
- 库文件:libmi_ipu.so
-
注意
- Cancel invoke功能只能取消本进程内的invoke任务,不能跨进程使用。
-
举例
Thread-0: s32Ret =MI_IPU_Invoke(u32ChnId, &inputV, &outputV); OR s32Ret = MI_IPU_Invoke2(u32ChnId, &stInvokeParam, &stRuntimeInfo); OR s32Ret = MI_IPU_Invoke2Custom(channel, &stInvokeParam, NULL); if (s32Ret == E_IPU_ERR_INVOKE_CANCELED) { printf("invoke has been canceled\n"); } Thread-1: s32Ret = MI_IPU_CancelInvoke(u32ThreadId, u32ChnId); if (s32Ret == MI_SUCCESS) { printf("succeed to cancel invoke task, thread id=%u, channel id=%u\n", u32ThreadId, u32ChnId); } else if (s32Ret == E_IPU_ERR_NOT_FOUND) { printf("do not find invoke task belongs to thread id=%u, channel id=%u\n", u32ThreadId, u32ChnId); } else if (s32Ret == E_IPU_ERR_NOT_SUPPORT) { printf("do not support cancel invoke on this platform\n"); } else { printf("unexpected error=%d\n", s32Ret); }
2.20. MI_IPU_CreateCHNWithUserMem¶
-
功能
使用用户提供的MMA内存创建IPU通道。
-
语法
MI_S32 MI_IPU_CreateCHNWithUserMem(MI_IPU_CHN *ptChnId, MI_IPUChnAttr_t *pstChnAttr, MI_PHY u64ModelPA); -
参数
参数名称 描述 输入/输出 ptChnId 获取IPU通道ID的指针 输出 pstIPUChnAttr IPU通道描述信息结构体指针 输入 u64ModelPA 存放网络模型文件的MMA内存 输入 -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
注意
- MI_IPUChnAttr_t.u32BatchMax 为批处理的最大值,如果这个模型不需要使用批处理,则将该值设置为1或者0。
- MI_IPUChnAttr_t.u32InputBufDepth 为设定的输入预分配私有tensor buffer* u32BatchMax的个数,比如 0 or 1 or 2 or 3, 当设置为0时,表示buffer来源于外部。如果直接使用前级模块的输出MI buffer,建议此处设置input_depth为0避免内存浪费。
- MI_IPUChnAttr_t. u32OutputBufDepth为设定的输出预分配私有tensor buffer* u32BatchMax的个数, 比如 0 or 1 or 2 or 3,当设置为0时,表示buffer来源于外部,如MI_RGN模块。
- 如果创建的是one_buf batch模式网络模型,则不会预分配输入和输出buffer。
- IPU最大通道数为48。
- 只有在调用MI_IPU_DestroyCHN后才能释放u64ModelPA
-
举例
MI_S32 s32Ret, buf_depth = 3, batch_max = 1; MI_IPU_CHN u32ChnId = 0; MI_IPUChnAttr_t chnAttr; MI_S32 fd, s32ModelSize; MI_U64 u64ModelPA = 0; void *pmem = NULL; void *pModelVA = NULL; char *pModelPath = "caffe_mobilenet_v2.tflite_sgsimg.img"; chnAttr.u32InputBufDepth = buf_depth; chnAttr.u32OutputBufDepth = buf_depth; chnAttr.u32BatchMax = batch_max; fd = open(pModelPath, O_RDONLY); if (fd < 0) { perror("Fail to open model!\n"); return -1; } s32ModelSize = lseek(fd, 0, SEEK_END); pmem = mmap(NULL, s32ModelSize, PROT_READ, MAP_SHARED, fd, 0); if (pmem == MAP_FAILED) { perror("mmap"); close(fd); return -1; } s32Ret = MI_SYS_MMA_Alloc(0, NULL, s32ModelSize, &u64ModelPA); if (s32Ret != MI_SUCCESS) { printf("fail to allocate model buf!\n"); munmap(pmem, s32ModelSize); close(fd); return s32Ret; } s32Ret = MI_SYS_Mmap(u64ModelPA, s32ModelSize, &pModelVA, TRUE); if (s32Ret != MI_SUCCESS) { printf("fail to mmap"); MI_SYS_MMA_Free(0, u64PhyAddr); munmap(pmem, s32ModelSize); close(fd); return s32Ret; } memcpy(pModelVA, pmem, s32ModelSize); MI_SYS_FlushInvCache(pModelVA, s32ModelSize); s32Ret = MI_IPU_CreateCHNWithUserMem(&u32ChnId, &chnAttr, u64ModelPA); if (s32Ret != MI_SUCCESS) { printf("fail to create ipu channel\n"); MI_SYS_Munmap(pModelVA, s32ModelSize); MI_SYS_MMA_Free(0, u64PhyAddr); munmap(pmem, s32ModelSize); close(fd); return s32Ret; }
2.21. MI_IPU_DestroyDeviceExt¶
-
功能
使用参数销毁IPU设备。
-
语法
MI_S32 MI_IPU_DestroyDeviceExt(MI_IPU_DevAttr_t *pstIPUDevAttr); -
返回值
-
MI_SUCCESS成功。
-
非MI_SUCCESS失败,参照错误码。
-
-
依赖
-
头文件:mi_ipu.h
-
库文件:libmi_ipu.so
-
-
举例
MI_S32 s32Ret; MI_IPU_DevAttr_t stDevAttr; stDevAttr.u32MaxVariableBufSize = BufSize; /*模型内部Tensor使用的memory的最大size*/ stDevAttr.u32VariableGroup = 0; stDevAttr.u32CoreMask = IPU_DEV_0; s32Ret = MI_IPU_CreateDevice(&stDevAttr, NULL, NULL, 0); if (s32Ret != MI_SUCCESS) { printf("fail to create ipu device\n"); return s32Ret; } ... MI_IPU_DestroyDeviceExt(&stDevAttr);
3. 数据类型¶
3.1. 数据类型定义¶
| 数据类型 | 定义 |
|---|---|
| SerializedReadFunc | 定义用于客制化的读取文件方式,用于支持客制化的AI网络存储格式 |
| MI_IPU_ELEMENT_FORMAT | 定义IPU输入数据枚举类型 |
| MI_IPU_BatchMode_e | 定义IPU batch buffer模式枚举类型 |
| MI_IPU_LayoutType_e | 定义tensor的排布枚举类型 |
| MI_IPU_IpuWorkMode_e | 定义IPU模型的工作模式枚举类型 |
| MI_IPU_TensorDesc_t | 定义IPU Tensor形状结构体 |
| MI_IPU_SubNet_InputOutputDesc_t | 定义IPU子网络输入/输出描述结构体 |
| MI_IPU_Tensor_t | 定义IPU Tensor地址结构体 |
| MI_IPU_TensorVector_t | 定义IPU Tensor数组结构体指针 |
| MI_IPU_DevAttr_t | 定义IPU设备属性结构体 |
| MI_IPU_ChnAttr_t | 定义IPU通道属性结构体 |
| MI_IPU_BatchInvoke_param_t | 定义批处理参数结构体 |
| MI_IPU_RuntimeInfo_t | 定义IPU运行信息结构体 |
| MI_IPU_OfflineModelStaticInfo_t | 定义IPU离线模型静态信息结构体 |
3.2. SerializedReadFunc¶
-
说明
定义用于客制化的读取文件方式,用于支持客制化的AI网络存储格式。
-
语法
typedef int (*SerializedReadFunc)(void *dst_buf,int offset, int size, char *ctx); -
成员
成员名称 描述 dst_buf 数据存放地址 offset 文件指针偏移量 size 读取大小 ctx 文件路径
3.3. MI_IPU_ELEMENT_FORMAT¶
-
说明
定义IPU输入数据枚举类型。
-
语法
typedef enum { MI_IPU_FORMAT_U8, MI_IPU_FORMAT_NV12, MI_IPU_FORMAT_INT16, MI_IPU_FORMAT_INT32, MI_IPU_FORMAT_INT8, MI_IPU_FORMAT_FP32, MI_IPU_FORMAT_UNKNOWN, MI_IPU_FORMAT_ARGB8888, MI_IPU_FORMAT_ABGR8888, MI_IPU_FORMAT_GRAY, MI_IPU_FORMAT_COMPLEX64, } MI_IPU_ELEMENT_FORMAT; -
成员
成员名称 描述 MI_IPU_FORMAT_U8 U8类型 MI_IPU_FORMAT_NV12 NV12类型,如YUV MI_IPU_FORMAT_INT16 INT16类型 MI_IPU_FORMAT_INT32 INT32类型 MI_IPU_FORMAT_INT8 INT8类型 MI_IPU_FORMAT_FP32 FLOAT类型 MI_IPU_FORMAT_UNKNOWN Unknown MI_IPU_FORMAT_ARGB8888 ARGB8888类型 MI_IPU_FORMAT_ABGR8888 ABGR8888类型 MI_IPU_FORMAT_GRAY GRAY类型 MI_IPU_FORMAT_COMPLEX64 COMPLEX64 类型 -
注意事项
-
ARGB/RGB/BGR tensor属于MI_IPU_FORMAT_U8数据类型
-
只有input tensor可以支援MI_IPU_FORMAT_NV12格式
-
只有output tensor可以支援MI_IPU_FORMAT_FP32格式
-
3.4. MI_IPU_BatchMode_e¶
-
说明
定义IPU batch buffer模式枚举类型。
-
定义
typedef enum { E_IPU_BATCH_N_BUF_MODE = 0, E_IPU_BATCH_ONE_BUF_MODE, } MI_IPU_BatchMode_e; -
成员
成员名称 描述 E_IPU_BATCH_N_BUF_MODE 模型为n_buf batch模式 E_IPU_BATCH_ONE_BUF_MODE 模型为one_buf batch模式 -
相关数据类型及接口
3.5. MI_IPU_LayoutType_e¶
-
说明
定义tensor的排布枚举类型。
-
定义
typedef enum { E_IPU_LAYOUT_TYPE_NHWC = 0, E_IPU_LAYOUT_TYPE_NCHW, } MI_IPU_LayoutType_e; -
成员
成员名称 描述 E_IPU_LAYOUT_TYPE_NHWC 该tensor为NHWC排布 E_IPU_LAYOUT_TYPE_NCHW 该tensor为NCHW排布 -
相关数据类型及接口
3.6. MI_IPU_IpuWorkMode_e¶
-
说明
定义IPU模型的工作模式枚举类型。
-
定义
typedef enum { E_IPU_IPU_WORK_MODE_SINGLECORE = 0, E_IPU_IPU_WORK_MODE_MULTICORE, } MI_IPU_IpuWorkMode_e; -
成员
成员名称 描述 E_IPU_IPU_WORK_MODE_SINGLECORE 模型为单核模式 E_IPU_IPU_WORK_MODE_MULTICORE 模型为多核模式 -
相关数据类型及接口
3.7. MI_IPU_TensorDesc_t¶
-
说明
定义IPU Tensor描述结构体。
-
语法
typedef struct MI_IPU_TensorDesc_s { MI_U32 u32TensorDim; MI_IPU_ELEMENT_FORMAT eElmFormat; MI_U32 u32TensorShape[MI_IPU_MAX_TENSOR_DIM]; MI_S8 name[MAX_TENSOR_NAME_LEN]; MI_U32 u32InnerMostStride; MI_FLOAT fScalar; MI_S64 s64ZeroPoint; MI_S32 s32AlignedBufSize; MI_U32 u32BufSize; MI_U32 u32InputWidthAlignment; MI_U32 u32InputHeightAlignment; MI_IPU_LayoutType_e eLayoutType; MI_U32 au32Reserve[4]; // reserved } MI_IPU_TensorDesc_t; -
成员
成员名称 描述 u32TensorDim Tensor维度 eElmFormat Tensor数据类型 u32TensorShape Tensor形状数组 name Tensor名称 u32InnerMostStride Tensor最内维长度(单位字节) fScalar Tensor量化系数 s64ZeroPoint Tensor量化offset s32AlignedBufSize Tensor buffer对齐后的大小 u32BufSize Tensor buffer大小 u32InputWidthAlignment 输入Tensor水平方向对齐大小 u32InputHeightAlignment 输入Tensor垂直方向对齐大小 eLayoutType Tensor的排布模式 au32Reserve 预留位 -
注意事项
-
Tensor维度最大为10。建议使用如下宏定义:
#define MI_IPU_MAX_TENSOR_DIM (10) -
输入数据必须严格按照u32InputWidthAlignment和u32InputHeightAlignment对齐,否则结果会出错。
-
数据对齐方式
input_formats 板上运行时数据对齐方式 RGB/BGR 不用对齐 RGBA/BGRA W = ALIGN_UP(W * 4, input_width_alignment) / 4
input_width_alignment默认为1YUV_NV12 H = ALIGN_UP(H, input_height_alignment)
input_height_alignment默认为2
W = ALIGN_UP(W, input_width_alignment)
input_width_alignment默认为2GRAY H = ALIGN_UP(H, input_height_alignment)
input_height_alignment默认为1
W = ALIGN_UP(W, input_width_alignment)
input_width_alignment默认为1RAWDATA_F32_NHWC 不用对齐 RAWDATA_S16_NHWC 不用对齐
-
3.8. MI_IPU_SubNet_InputOutputDesc_t¶
-
说明
定义IPU子网络输入/输出描述结构体。
-
语法
typedef struct MI_IPU_SubNet_InputOutputDesc_s { MI_U32 u32InputTensorCount; MI_U32 u32OutputTensorCount; MI_IPU_TensorDesc_t astMI_InputTensorDescs[MI_IPU_MAX_INPUT_TENSOR_CNT]; MI_IPU_TensorDesc_t astMI_OutputTensorDescs[MI_IPU_MAX_OUTPUT_TENSOR_CNT]; } MI_IPU_SubNet_InputOutputDesc_t; -
成员
成员名称 描述 u32InputTensorCount 输入Tensor个数 u32OutputTensorCount 输出Tensor个数 astMI_InputTensorDescs 输入Tensor形状结构体数组 astMI_OutputTensorDescs 输出Tensor形状结构体数组
3.9. MI_IPU_Tensor_t¶
-
说明
定义IPU Tensor地址结构体。
-
语法
typedef struct MI_IPU_Tensor_s { void *ptTensorData[2]; MI_PHY phyTensorAddr[2];//notice that this is miu bus addr,not cpu bus addr. } MI_IPU_Tensor_t; -
成员
成员名称 描述 ptTensorData Tensor buffer虚拟地址 phyTensorAddr Tensor buffer物理地址
3.10. MI_IPU_TensorVector_t¶
-
说明
定义IPU Tensor数组结构体。
-
语法
typedef struct MI_IPU_TensorVector_s { MI_U32 u32TensorCount; MI_IPU_Tensor_t astArrayTensors[MI_IPU_MAX_TENSOR_CNT]; } MI_IPU_TensorVector_t; -
成员
成员名称 描述 u32TensorCount Tensor个数 astArrayTensors 每个Tensor的地址信息
3.11. MI_IPU_DevAttr_t¶
-
说明
定义IPU设备属性结构体。
-
语法
typedef struct MI_IPU_DevAttr_s { MI_U32 u32MaxVariableBufSize; MI_U32 u32YUV420_W_Pitch_Alignment; // unused MI_U32 u32YUV420_H_Pitch_Alignment; // unused MI_U32 u32XRGB_W_Pitch_Alignment; // unused MI_U32 u32VariableGroup; // variable group ID MI_U32 u32CoreMask; // ipu core mask MI_U32 au32Reserve[6]; // reserve } MI_IPU_DevAttr_t; -
成员
成员名称 描述 u32MaxVariableBufSize 模型内部Tensor使用的memory的最大大小 u32YUV420_W_Pitch_Alignment Unused u32YUV420_H_Pitch_Alignment Unused u32XRGB_W_Pitch_Alignment Unused u32VariableGroup variable内存组ID u32CoreMask IPU核掩码 au32Reserve 预留位
3.12. MI_IPU_ChnAttr_t¶
-
说明
定义IPU通道属性结构体。
-
语法
typedef struct MI_IPU_ChnAttr_s { MI_U32 u32SubNetId; MI_U32 u32OutputBufDepth; MI_U32 u32InputBufDepth; MI_U32 u32BatchMax; MI_U32 au32Reserve[8]; // reserved } MI_IPUChnAttr_t; -
成员
成员名称 描述 u32SubNetId 子网络ID u32OutputBufDepth 输出Tensor Buffer深度 u32InputBufDepth 输入Tensor Buffer深度 au32Reserve 预留位 -
注意事项
IPU输入/输出缓冲区最大深度为3。建议使用如下宏定义:
#define MAX_IPU_INPUT_OUTPUT_BUF_DEPTH (3)
3.13. MI_IPU_BatchInvoke_param_t¶
-
说明
定义批处理参数结构体。
-
语法
typedef struct MI_IPU_BatchInvoke_param_s { MI_PHY u64VarBufPhyAddr; MI_U32 u32VarBufSize; MI_U32 u32BatchN; MI_S32 s32TaskPrio; MI_U32 u32IpuAffinity; MI_IPU_Tensor_t astArrayTensors[MI_IPU_MAX_BATCH_TENSOR_CNT]; MI_U32 au32Reserve[8]; // reserved } MI_IPU_BatchInvoke_param_t; -
成员
成员名称 描述 u64VarBufPhyAddr 用户指定的variable buffer物理地址 u32VarBufSize 用户指定的variable buffer大小 u32BatchN 批处理个数 s32TaskPrio 任务优先级 u32IpuAffinity 绑定ipu core astArrayTensors 批处理所有的输入输出tensor buffer地址 au32Reserve 预留位 -
注意事项
-
astArrayTensors数组存放批处理所有的输入输出tensor buffer地址,规则是先依次存入所有输入tensor buffer地址,再存入所有输出tensor buffer地址。
-
每一个输入/输出tensor的起始物理地址必须64 bytes 对齐。
-
用户指定的variable buffer的起始物理地址必须64 bytes对齐。
-
3.14. MI_IPU_RuntimeInfo_t¶
-
说明
定义IPU运行信息结构体。
-
语法
typedef struct MI_IPU_RuntimeInfo_s { MI_U64 u64BandWidth; MI_U64 u64IpuTime; MI_U64 u64BandWidthRead; MI_U64 u64BandWidthWrite; MI_U32 au32Reserve[8]; // reserved } MI_IPU_RuntimeInfo_t; -
成员
成员名称 描述 u64BandWidth 带宽数据总量 (bytes) u64IpuTime IPU处理时间 (us) u64BandWidthRead 带宽数据读总量 (bytes) u64BandWidthWrite 带宽数据写总量 (bytes) au32Reserve 预留位
3.15. MI_IPU_OfflineModelStaticInfo_t¶
-
说明
定义IPU离线模型静态信息结构体。
-
语法
typedef struct MI_IPU_OfflineModelStaticInfo_s { MI_U32 u32VariableBufferSize; MI_U32 u32OfflineModelSize; MI_IPU_BatchMode_e eBatchMode; MI_U32 u32TotalBatchNumTypes; MI_U32 au32BatchNumTypes[MI_IPU_MAX_BATCH_TYPE_NUM]; MI_IPU_IpuWorkMode_e eIpuWorkMode; MI_U32 au32Reserve[8]; // reserved } MI_IPU_OfflineModelStaticInfo_t; -
成员
成员名称 描述 u32VariableBufferSize 离线模型运行需要的variable buffer size u32OfflineModelSize 离线模型文件大小 eBatchMode 离线模型batch buffer模式 u32TotalBatchNumTypes 离线模型所支持的batch数的种类个数 au32BatchNumTypes n_buf模式:离线模型板端运行所能够支持的最大batch数以及batch数推荐值的最大值
one_buf模式:离线模型板端运行所能够支持的batch数的种类eIpuWorkMode 离线模型的工作模式 au32Reserve 预留位 -
注意事项
-
如果模型的eBatchMode为E_IPU_BATCH_N_BUF_MODE:
u32TotalBatchNumTypes将会返回2。
au32BatchNumTypes[0]将会返回该离线模型板端运行所能够支持的最大batch数。
au32BatchNumTypes[1]将会返回该离线模型板端运行的推荐batch数中的最大值。(推荐batch数将是2的n次幂,当au32BatchNumTypes[1] = 2n,代表该模型的推荐batch数为20, 21, ..., 2(n-1), 2n)。
Ex:
au32BatchNumTypes[0]返回128,则可以支持1~128个batches。
au32BatchNumTypes[1]返回8,则该模型的推荐batch数为1, 2, 4, 8。
-
如果模型的eBatchMode为E_IPU_BATCH_ONE_BUF_MODE:
u32TotalBatchNumTypes将会返回离线模型板端运行所能够支持的batch数的种类的个数。
au32BatchNumTypes[0] ~ au32BatchNumTypes[u32TotalBatchNumTypes - 1]将会返回离线模型板端运行所能够支持的batch数的种类。
Ex:
u32TotalBatchNumTypes==3
au32BatchNumTypes[0]==10
au32BatchNumTypes[1]==20
au32BatchNumTypes[2]==30
则可以支持10、20、30这三种batch数。
-
4. 错误码¶
表4-1 IPU API错误码
| 错误代码 | 宏定义 | 描述 |
|---|---|---|
| 0 | MI_SUCCESS | Success |
| 1 | E_IPU_ERR_INVALID_CHNID | Invlalid channel ID |
| 2 | E_IPU_ERR_CHNID_EXIST | Channel already exists |
| 3 | E_IPU_ERR_CHNID_UNEXIST | Channel does not exist |
| 4 | E_IPU_ERR_NOMEM | Failure caused by malloc memory |
| 5 | E_IPU_ERR_NOBUF | Failure caused by malloc buffer |
| 6 | E_IPU_ERR_BADADDR | Bad address, buffer address is not gotten from IPU buffer allocator |
| 7 | E_IPU_ERR_SYS_TIMEOUT | System timeout |
| 8 | E_IPU_ERR_FILE_OPERATION | File cannot be opened or read or written |
| 9 | E_IPU_ERR_ILLEGAL_TENSOR_BUFFER_SIZE | Tensor buffer size does not meet the requirement, usually less than the requirement |
| 10 | E_IPU_ERR_ILLEGAL_BUFFER_DEPTH | Input or output buffer depth quantum exceeds maximum number |
| 11 | E_IPU_ERR_ILLEGAL_INPUT_OUTPUT_DESC | Network description is illegal, usually input or output buffer quantum is wrong |
| 12 | E_IPU_ERR_ILLEGAL_INPUT_OUTPUT_PARAM | Uer's input or output buffer quantum does not match network description |
| 13 | E_IPU_ERR_MAP | Address mapping error |
| 14 | E_IPU_ERR_INIT_FIRMWARE | Fail to initialize IPU firmware |
| 15 | E_IPU_ERR_CREATE_CHANNEL | Fail to create channel |
| 16 | E_IPU_ERR_DESTROY_CHANNEL | Fail to destroy channel |
| 17 | E_IPU_ERR_INVOKE | Fail to invoke |
| 18 | E_IPU_ERR_SET_MALLOC_REGION | Fail to set malloc region for freertos |
| 19 | E_IPU_ERR_SET_IPU_PARAMETER | Fail to set IPU parameter |
| 20 | E_IPU_ERR_INVALID_PITCH_ALIGNMENT | Invalid pitch alignment |
| 21 | E_IPU_ERR_NO_CREATED_IPU_DEVICE | There is no created IPU device |
| 22 | E_IPU_ERR_GET_IPU_VERSION | Fail to get IPU version from IPU firmware |
| 23 | E_IPU_ERR_MISMATCH_IPU_HEAD_FILE | IPU head files version not matched |
| 24 | E_IPU_ERR_NO_SUPPORT_REQ | IPU firmware does not support this request |
| 25 | E_IPU_ERR_FAILED | Unexpected error |
| 26 | E_IPU_ERR_SEND_REQUEST | Fail to send request to IPU |
| 27 | E_IPU_ERR_GET_FIRMWARE_INFO | Fail to get ipu firmware information |
| 28 | E_IPU_ERR_INVALID_IPUCORE_BOOTING_PARAM | Invalid IPU cores booting parameters |
| 29 | E_IPU_ERR_INVALID_IPUCORE_SHUTDOWNING_PARAM | Invalid IPU cores shutdowning parameters |
| 30 | E_IPU_ERR_NO_MULTICORE_ENV | Multicore mode needs all ipu cores being alive |
| 31 | E_IPU_ERR_INVALID_TASK_PRIORITY | Invalid ipu task priority |
| 32 | E_IPU_ERR_DEV_SHUTDOWN | Ipu core has been shutdown |
| 33 | E_IPU_ERR_DEV_FAIL_RESET | Fail to reset ipu |
| 34 | E_IPU_ERR_DEV_FAIL_SHUTDOWN | Fail to shutdown ipu |
| 35 | E_IPU_ERR_NO_AVAILABLE_DEV | No available ipu dev |
| 36 | E_IPU_ERR_RESET_OFF | Reset function is off |
| 37 | E_IPU_ERR_INVALID_BATCH_NUM | batch number error |
| 38 | E_IPU_ERR_BATCH_TYPE | batch type error |
| 39 | E_IPU_ERR_BATCH_MODE | batch mode error |
| 40 | E_IPU_ERR_NO_AVAILABLE_BATCH_MODE | do not find available batch mode |
| 41 | E_IPU_ERR_IPU_HANG | invoke was dropped due to ipu hang |
| 42 | E_IPU_ERR_NO_RESET_DEV | no reset ipu dev |
| 43 | E_IPU_ERR_NO_BATCH_PARAM | no batch parameter |
| 44 | E_IPU_ERR_INVALID_MODEL_BUFFER | invalid user model buffer physical address or size |
| 45 | E_IPU_ERR_INVALID_VARIABLE_BUFFER | invalid variable buffer physical address or size |
| 46 | E_IPU_ERR_NOT_ASSIGN_CORE | not assign ipu core when use user's variable buffer |
| 47 | E_IPU_ERR_SWDISP_NOT_REGISTER | model has unsupported swdisp function |
| 48 | E_IPU_ERR_SWDISP_NOT_FIND_TASKID | not find swdisp task id |
| 49 | E_IPU_ERR_SWDISP_INVALID_PARAM | invalid swdisp parameter |
| 50 | E_IPU_ERR_SWDISP_UNEXPECTED | unexpected swdisp error |
| 51 | E_IPU_ERR_SWDISP_UNKNOWN | unknown swdisp error |
| 52 | E_IPU_ERR_BAD_PHY_ADDR_ALIGNMENT | ipu buffer physical addr not aligned |
| 53 | E_IPU_ERR_MISMATCH_INVOKE_FUNC | n_buf/one_buf batch model should use MI_IPU_Invoke2/MI_IPU_Invoke2Custom |
| 54 | E_IPU_ERR_MISMATCH_MODEL | other platform's model |
| 55 | E_IPU_ERR_INVOKE_CANCELED | invoke has been canceled |
| 56 | E_IPU_ERR_INVOKE_CANCEL_FAIL | fail to cancel invoke |
| 57 | E_IPU_ERR_NOT_SUPPORT_CANCELINVOKE | do not support cancel invoke |
| 58 | E_IPU_ERR_PERMISSION_DENIED | permission denied |
| 59 | E_IPU_ERR_INVOKE_INTERRUPT | invoke task was interrupted (maybe on suspend), please try again |
| 256 | E_IPU_ERR_NO_AVAILABLE_CHNID | There is no available channel |
5. PROCFS介绍¶
5.1. 概述¶
通过控制台debug IPU的方式是procfs。
-
IPU Procfs在open device(mi_dev)的时候创建节点
proc/mi_modules/mi_ipu/mi_ipu0,close device的时候删除节点。 -
IPU Procfs在insmod ko的时候创建节点
/proc/mi_modules/mi_ipu/debug_hal/xxx。
5.2. 如何看MMA信息¶
# cat /proc/mi_modules/mi_sys/mi_sys0

可以看到所有MMA的使用情况。
# cat /proc/mi_modules/mi_ipu/mi_ipu0

可以看IPU的device和各channel使用MMA的情况。
5.3. 查看IPU version信息¶
# cat /proc/mi_modules/mi_ipu/debug_hal/version

5.4. 查看IPU clock信息¶
# cat /proc/mi_modules/mi_ipu/debug_hal/freq

5.5. 调节IPU clock¶
# echo xxx > /proc/mi_modules/mi_ipu/debug_hal/freq
*(XXX必须是available frequency)*

5.6. 开关auto reset功能¶
Auto reset功能可以在IPU无响应后reset IPU,继续未完成的任务。
打开auto reset功能:echo on > /proc/mi_modules/mi_ipu/debug_hal/auto_reset
关闭auto reset功能:echo off > /proc/mi_modules/mi_ipu/debug_hal/auto_reset
前期测试阶段,建议关闭auto reset功能,理清IPU无响应的原因。
5.7. 抓取IPU log¶
# echo “ctrl_size=0x800000 corectrl_size=0x800000 ctrl=0xffffff corectrl=0x1fff” > /proc/mi_modules/mi_ipu/debug_hal/ipu_log
ctrl_size和corectrl_size是为ctrl log和corectrl log分配buffer的大小,ctrl和corectrl是ctrl log和corectrl log的配置。