MI IPU API


REVISION HISTORY

Revision No.
Description
Date
3.0
  • Initial release
  • 07/23/2021
  • Added PROCFS introduction
  • 08/25/2021
  • Modify default ipu firmware file path
  • Modify parameter(pReadCtx) description of MI_IPU_CreateCHN
  • Modify maximum channel number
  • Modify the usage of tensor shape
  • Modify maximum tensor dimension
  • Modify error codes
  • Modify ipu frequency path on /sys
  • 11/30/2021
  • Add swdisp related error codes
  • Add u64BandWidthRead/u64BandWidthWrite to MI_IPU_RuntimeInfo_t structure
  • Add ipu buffer alignment error code
  • 12/21/2021
  • Modify IPU buffer alignment number
  • 01/20/2022
  • Add MI_IPU_Invoke2Custom function
  • Modify error codes
  • Add MI_IPU_FORMAT_GRAY tensor format
  • Add member 'u32BufSize', 'u32InputWidthAlignment', 'u32InputHeightAlignment', 'bOutputNCHW' in MI_IPU_TensorDesc_t
  • 02/25/2022
  • Add error code ‘E_IPU_ERR_MISMATCH_MODEL’
  • 06/01/2022
  • Add enum type ‘MI_IPU_BatchMode_e’, ‘MI_IPU_LayoutType_e’, ‘MI_IPU_IpuWorkMode_e’
  • Modify member ‘bOutputNCHW’ to ‘eLayoutType’ and add new member ‘au32Reserve[4]’ in MI_IPU_TensorDesc_t
  • Add new member ‘au32Reserve[8]’ in MI_IPU_DevAttr_t
  • Add new member ‘au32Reserve[8]’ in MI_IPUChnAttr_t
  • Add new member ‘au32Reserve[8]’ in MI_IPU_BatchInvokeParam_t
  • Add new member ‘au32Reserve[8]’ in MI_IPU_RuntimeInfo_t
  • Add new member ‘au32Reserve[8]’, ‘eBatchMode’, ‘u32TotalBatchNumTypes’, ‘au32BatchNumTypes[MI_IPU_MAX_BATCH_TYPE_NUM]’, ‘eIpuWorkMode’ in MI_IPU_OfflineModelStaticInfo_t
  • 06/13/2022
  • In MI_IPU_RuntimeInfo_t, comment the unit of ‘u64IpuTime’ as us.
  • In MI_IPU_OfflineModelStaticInfo_t, add description for ‘au32BatchNumTypes[1]’ as max batchNum suggested.
  • In MI_IPU_ELEMENT_FORMAT, add tensor format ‘MI_IPU_FORMAT_COMPLEX64’
  • 08/15/2022
  • Add API ‘MI_S32 MI_IPU_CancelInvoke(MI_U32 u32ThreadId,MI_IPU_CHN u32ChnId)’.
  • Add error codes.
  • 05/25/2023
  • Add API ‘MI_S32 MI_IPU_CreateCHNWithUserMem(MI_IPU_CHN *ptChnId, MI_IPUChnAttr_t *pstChnAttr, MI_PHY u64ModelPA)’.
  • Add API ‘MI_S32 MI_IPU_DestroyDeviceExt(MI_IPU_DevAttr_t *pstIPUDevAttr)'.
  • Add new members ‘u32VariableGroup’, 'u32CoreMask' in MI_IPU_DevAttr_t
  • 09/26/2023
  • Add error codes ‘E_IPU_ERR_PERMISSION_DENIED’, ‘E_IPU_ERR_INVOKE_INTERRUPT’
  • 07/25/2024
  • Update Model Description.
  • Add Basic Structure, Module Function, Application Scenario, Chip Difference, Principle, Interface Call and Example parts.
  • 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。

    图1-1 IPU推理流程框图

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

    图1-2 MI IPU的使用方式


    1.3. 功能介绍

    MI IPU支持以下功能:

    1. 支持多线程、多进程执行模型推理

    2. 支持多通道

    3. 支持为模型自动分配buffer,同时也支持由用户来分配buffer

    4. 支持指定IPU推理任务的优先级

    5. 支持单次推理单张输入和单次推理多张输入


    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-3 MI IPU工作原理示意图


    1.7. 接口调用

    当执行模型推理时,MI IPU的接口调用通常分为以下步骤:

    1. 解析模型信息,获取模型所需的variable buffer大小

    2. 创建IPU设备

    3. 创建IPU通道

    4. 获取IPU通道的输入、输出描述符

    5. 获取输入buffer的地址,并将输入内容拷贝到此buffer,然后flush cache,确保buffer与cache中内容相同

    6. 获取输出buffer的地址

    7. 执行模型推理

    8. 归还前述获取的输入、输出buffer到通道所有buffer

    9. 销毁IPU通道

    10. 销毁IPU设备

    图1-4 MI IPU接口调用流程图


    1.8. 实例介绍


    1.8.1. dla_classify

    dla_classify适用于推演分类模型,此时模型的输入格式要求为BGR或RGB。在运行时,该示例首先加载离线模型文件,并驱动IPU对输入图片进行分类,最后打印前5名的分类预测结果和对应的置信度。具体代码可参考/sdk/veriy/release_feature/source/dla/dla_classify/dla_classify.cpp。

    #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对输入图片进行推理检测,最后在当前目录下输出带有检测结果框的图片。具体代码可参考/sdk/veriy/release_feature/source/dla/dla_detect/dla_detect.cpp。


    1.8.3. dla_classifyNBatch

    dla_classifyNBatch同样用于推演分类模型,对于模型及输入的要求与dla_classify相同。不同之处在于,该示例展示了调用MI_IPU_Invoke2和MI_IPU_Invoke2Custom时输入、输出内存的排布方式,和用户自己分配内存时需要调用的接口和内存对齐等注意事项。具体代码可参考/sdk/veriy/release_feature/source/dla/dla_classifyNBatch/dla_classifyNBatch.cpp。


    1.8.4. dla_simulator

    dla_simulator用于在板端推理模型,并与PC端IPU SDK工具链提供的simulator.py的运行结果进行比对,从而在板端验证模型推理的正确性。该示例适用的模型为经IPU SDK工具链转换的离线模型,模型输入及格式由模型自身决定。具体代码可参考/sdk/veriy/release_feature/source/dla/dla_simulator/dla_simulator.cpp。


    1.8.5. dla_simulatorNBatch

    dla_simulatorNBatch同样用于推理板端模型,其适用模型和输入要求同dla_simulator。不同之处在于,dla_simulatorNBatch示例中调用MI_IPU_Invoke2接口,支持单次推理多张输入。具体代码可参考/sdk/veriy/release_feature/source/dla/dla_simulatorNBatch/dla_simulatorNBatch.cpp。


    1.8.6. dla_show_img_info

    dla_show_img_info用于展示板端推理离线模型的帧率和带宽统计数据,还可以抓取IPU log来分析模型每层性能。其输入为经过IPU SDK工具链转换的任意模型。具体代码可参考/sdk/veriy/release_feature/source/dla/dla_show_img_info/dla_show_img_info.cpp。


    1.8.7. ipu_log

    ipu_log工具用于在需要分析模型每层性能时抓取IPU log。该工具也集成在dla_show_img_info中。IPU log的开启方法参考抓取IPU log。具体代码可参考/sdk/veriy/release_feature/source/dla/ipu_log/ipu_log.c。


    1.8.8. ipu_utilization

    ipu_utilization用于打印IPU的使用率。当应用程序调用MI IPU接口推理模型时,可运行该工具查看IPU的使用率情况。具体代码可参考/sdk/veriy/release_feature/source/dla/ipu_utilization/ipu_utilization.c。


    1.8.9. ipu_server

    ipu_server用于创建IPU的推理服务,在PC端使用python接口推理模型。首先在板端运行该工具并配置端口号,然后在PC端使用IPU SDK工具链提供的rpc_simulator.py连接板端IP和配置的端口号。该工具可推理任意模型,运行结果保存在PC端当前目录下的log/output里。更多rpc_simulator的使用可参考IPU SDK用户文档。具体代码可参考 /sdk/veriy/release_feature/source/dla/ipu_server/ipu_server.cpp。


    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种方式:

        1. 通过MI_IPU_GetInputTensors分配Buffer;

        2. 使用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种方式:

      1. 通过MI_IPU_GetInputTensors2分配Buffer;

      2. 使用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模式
    • 相关数据类型及接口

      MI_IPU_OfflineModelStaticInfo_t

      MI_IPU_GetOfflineModeStaticInfo

    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排布
    • 相关数据类型及接口

      MI_IPU_TensorDesc_t

      MI_IPU_GetInOutTensorDesc

    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 模型为多核模式
    • 相关数据类型及接口

      MI_IPU_OfflineModelStaticInfo_t

      MI_IPU_GetOfflineModeStaticInfo


    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默认为1
        YUV_NV12 H = ALIGN_UP(H, input_height_alignment)
        input_height_alignment默认为2
        W = ALIGN_UP(W, input_width_alignment)
        input_width_alignment默认为2
        GRAY H = ALIGN_UP(H, input_height_alignment)
        input_height_alignment默认为1
        W = ALIGN_UP(W, input_width_alignment)
        input_width_alignment默认为1
        RAWDATA_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的配置。