MI SYS Debug SOP


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 12/21/2023

    前言

    本文为FAE及软件开发相关人员而写,旨在介绍开发过程中客户遇到MI SYS相关问题时,如何自行进行初步排查,确定是Sigmastar SDK问题后再提供相关信息给RD分析。


    1. MMU 踩内存问题

    1. 出现以下log,说明发生了MMU踩内存。

      [MI WRN] MI_SYS_Mma_MmuCallback[227]: [MI_SYS_Mma_MmuCallback] Status=0x2, PhyAddr=0x40070000, ClientId=0x70,Name=CPU_CA35 IsWrite=0
      
      • Status
        • 触发该回调的原因,当前值为0x2,属于非法读写操作。
      • PhyAddr

        • 访问触发异常的entry起始地址,当前值为0x40070000
      • ClientId

        • 模块id,当前值为0x70
      • Name

        • 模块名,当前值为CPU
      • IsWrite

        • 读写操作,1是写,0是读,当前值为0,是读操作。
    2. 分析

      • 运行应用前输入以下命令收集mma内存申请和释放的详细信息

        echo debug_mmu debug_log 1 > /proc/mi_modules/mi_sys/mi_sys0
        

        若PhyAddr位于某个已经释放的 buff的fr和ed之间,说明模块访问了已经释放的内存。

        al:64000 sz:cac0 ed:70ac0 na:app-mmaAlloc
        fr:64000 sz:cac0 ed:70ac0  na:app-mmaAlloc
        [MI WRN] MI_SYS_Mma_MmuCallback[227]: [MI_SYS_Mma_MmuCallback] Status=0x2, PhyAddr=0x40070000, ClientId=0x70,Name=CPU_CA35 IsWrite=0
        

        由log可知,PhyAddr= 0x40070000,vpa的起始地址由/proc/mi_modules/mi_sys_mma/mma_heap_name0可得,当前vpa起始地址为0x40000000,所以PhyAddr相对vpa的起始地址的偏移地址为 0x70000,是在free的内存范围内(0x70000在0x64000-0x70ac0范围内),大概率是cpu 访问了释放后的app-mmaAlloc buff。

      • 若MmuCallback打印的PhyAddr不在已经free掉的内存地址范围中,怀疑是log太多,部分log被冲掉,此时已经确定踩内存的模块,那么可以只过滤对应模块的内存分配信息。

        echo debug_mmu debug_log [enable/disable] [enable/disable free]  [enable/disable alloc] [module id list] > /proc/mi_modules/mi_sys/mi_sys0
        

        例子:

        • enable vif ai alloc/free buf log
          echo debug_mmu debug_log 1 1 1 4,6 > /proc/mi_modules/mi_sys/mi_sys0
          
      • 若上述没有发现踩到free的buff,那么打开debugMmu进行debug,修改/config/modparam.json文件,在E_MI_MODULE_ID_SYS增加{"debugMmu" : 1},然后重启机器,运行应用。

        "E_MI_MODULE_ID_SYS" :
        {
        "cmdQBufSize" : 400,
        "debugmmu": 1
        },
        

        这时当HW多读或多写时可以100%抓到,打印类似以下log。

        al:1480000 sz:320000 ed:17a0000 na:vde_rec_0_0_0
        [MI WRN] MI_SYS_Mma_MmuCallback[425]: [MI_SYS_Mma_MmuCallback] Status=0x2, PhyAddr=0x401780000, ClientId=0x38,Name=VENC0_CODEC0_R  IsWrite=0
        

        首先计算出entry size:在开机后,cat /proc/mi_modules/mi_sys_mma/mma_heap_name0,其中heap_info 的length 除以 freeEntryNum 就是entry size。 此时mmu entry size 设置为128K ,若 PhyAddr+entry size=ed,那么可以说明模块发生了内存越界访问。上述log中,0x17a0000(ed)=0x1780000+0x20000(entry size),说明VENC0_CODEC0_R模块发生了内存越界访问。

      • 根据Name找对应模块owner,提供以上打印的log并告诉以上分析结论。

    2. MIU Protect问题

    当遇到如下log时,代表发生了miu protect:

    [HAL MIU ERR] [hal_miu_protect_show_hit_info@1301] [PROTECT] IP hit protect address.
    Hit block 32, address: 0x400800000<->0x400802000, whitelist: [CPU_CA55, ]
    Hit count: 1
    Hit IP : 0x45 - BDMA
    Hit MMU address: 0x400800000<->0x40080000f
    

    可以遵循如下步骤进行分析定位:

    1. 出现miu protcect的原因:“IP hit protect address”代表白名单之外的IP访问了受保护的地址;“IP write out of dram”代表IP访问了超出dram范围的地址或出现了MMU踩内存问题,需关闭kernel panic后观察是否出现MMU踩内存打印,进一步确认原因。(关闭kernel的方法见第5点
    2. 通过log中的信息,可以得知出问题的ip是bdma,他访问了block 32(该block地址范围是0x400800000<->0x400802000,白名单中设置了只允许CPU_CA55访问)中的0x400800000<->0x40080000f地址
    3. 寻求bdma ip owner的帮助,需要提供log以及当前场景下bdma的使用情况、传参调用等信息
    4. 默认在发生miu protect后出现kernel panic,如果不希望发生问题时panic,可以通过将modparam.json中的 "g_bEnableMiuPanic" 字段设为false实现,设置完后需要重启或重新加载mi_sys.ko
    5. 当前系统的miu protect情况可以通过cat /proc/mi_modules/mi_sys_mma/miu_protect获得,默认的策略是保护kernel lx_mem中除mma之外的所有内存,将bsp相关的ip设置为白名单,stream pipe相关的ip不允许访问

    3. 帧率不足问题

    帧率不足问题具体表现为:

    播放器拉流看对应的fps没有达到设定的数值

    若出现帧率不足问题,可以遵循如下步骤进行分析定位:

    1.watch -n 1 'cat /proc/mi_modules/mi_venc/mi_venc*'

    ---------------------------- OutputPort of dev: 0 -----------------------------
    ChnId  CODEC  Profile   BufSize MinAllocSize  RefNum  bByFrame  FrameCnt  DropCnt  ReEncCnt  RingUnreadCnt  RingTotalCnt   UsrLockedCnt
        0   H265        0   4147200         7273       0         1    871390        0         0              0             0              0
    
    
    -----------------------------------Input port common info for mi_venc  only dump enabled port-----------------------------------
      ChnId  PassId  PortId  user_buf_quota  UsrInjectQ_cnt  BindInQ_cnt     TotalPendingBuf_size  usrLockedInjectCnt
          0       0       0               4               0            4                 37601280                   0
      ChnId  PassId  PortId     curWorkingQ_cnt     workingTask_cnt      lazzyRewindTask_cnt
          0       0       0                   3                   1                        0
    

    查看 RingUnreadCnt/RingTotalCnt/UsrInjectQ_cnt/BindInQ_cnt 是否在2~4 变化,如果有,那说明是 APP 取流不够快,想证明确实是 APP 取流不够快,可以直接在 mi venc  内部就 drop 掉编码好的 es.

    echo drop_out a d > /proc/mi_modules/mi_venc/mi_venc0
    

    此时再观察 mi venc procfs 里面的 Fps_1s 字段,看帧率是否提上来了.

    ChnId  State  EnPred  base  enhance MaxStreamCnt  Fps_1s    kbps1s  Fps10s    kbps10s  lastQp
        0      0       0     0        0            3   29.99       964   29.98        929      20
    

    2.从后级模块往前级模块依次cat /proc/mi_modules/mi_xxx/mi_xxx*

    查看 InputPort 的 DropCnt 是否持续增加,持续增加说明是对应模块内部丢帧了

    ChnId  State  EnPred  base  enhance MaxStreamCnt  Fps_1s    kbps1s  Fps10s    kbps10s  lastQp
        0      0       0     0        0            3   12.99       964   13.58        929      20
    

    继续看GetIntoMaxCnt/GetIntoMmaLackCnt/GetIntoTotalCnt/GetIntoFrcCnt 是否在持续增长

      ChnId  PassId  PortId    GetFrame/Ms    FPS   FinishCnt   RewindCnt  GetTotalCnt    GetOkCnt    GetIntoMaxCnt  GetIntoMmaLackCnt   GetIntoTotalCnt  GetIntoFrcCnt
          0       0       0        13/1071  12.13      982123          10      1903946      982133                0                  0            921813              0
    

    -- GetIntoMaxCnt 增长说明MaxEnqTasks 用满了,可以设大试试。若有效则需要和对应的MI模块owner沟通,让MI模块owner 在驱动中修改MaxEnqTasks。

    echo set_Max_EnqTasks <eModuleId> <u8DevId> <u8PassId> <u16ChannelId> <EnqTasksNum> > /proc/mi_modules/mi_sys/mi_sys0
    
    echo set_Max_EnqTasks 23 0 1 0 5 > /proc/mi_modules/mi_sys/mi_sys0
    

    --GetIntoMmaLackCnt 增长说明MMA不够用了,可以bootargs设大试试,若有效则修改defconfig中CONFIG_MMA_MEM_SIZE字段的值为调整后的大小。

    --GetIntoTotalCnt 增长说明output port 的缓存可能不足,可以设大试试。若有效则修改APP代码,修改MI模块output port depth。若无效,则有可能是后级模块处理太慢,导致buffer堆积在后级模块,这时候需要分析后级模块处理慢的原因。

    echo set_ouputport_depth [Modid] [Devid] [Chnid] [Passid] [Portid] u32UserFrameDepth u32BufQueueDepth > > /proc/mi_modules/mi_sys/mi_sys0
    
    echo set_ouputport_depth23 0 0 1 0 0 6 > /proc/mi_modules/mi_sys/mi_sys0
    

    --GetIntoFrcCnt 增长说明是由于帧率控制导致的丢帧,一般来说就是一定存在帧率控制。

    3.根据第2步区分出是哪个模块跟原因,就可以找模块owner具体分析了,看模块HW 耗时是否正常,BW 是否正常,pipe是否超过规格

    1. 进入sdk/verify/mi_demo目录,make source/miu_server
    2. 将sdk/verify/mi_demo/out/arm/app/prog_miu_server拷贝到板端
    3. 在板端运行./prog_miu_server
    4. 使用 BWLA Tool 工具连接版端,查看 BW 数据

    4. MMA内存不足问题

    mma内存不足问题具体表现为:

    1. 应用或模块在调用MI_SYS_MMA_Alloc等内存分配接口时返回失败
    2. 模块发生丢帧,通过对应模块的proc info发现“GetIntoMmaLackCnt”字段在增加
    3. 其他

    cat /proc/mi_modules/mi_sys_mma/mma_heap_name0查看系统当前的mma使用情况,重点关注"length" "avail" "used" "HighPeak"四个字段。若avail小于要分配的大小,或length-HighPeak小于要分配的大小,代表可能出现内存不足问题;否则,代表可能出现内存碎片问题

    若出现内存不足问题,可以遵循如下步骤进行分析定位:

    1. 加大mma内存:

      1. 如果是pure linux系统,修改环境变量bootargs字段,将mma_heap_name0的sz加大
      2. 如果是dual os系统,可以通过修改环境变量 bootargs 去增大 mma_size,并相应地减小 LX_MEM、mma_base 的大小。其中 LX_MEM 要求1M 对齐。bootargs_rtos 的mma_base、mma_size 和 bootargs 的mma_base、mma_size 要保持一致。
    2. 检查/proc/mi_modules/mi_sys_mma/mma_heap_name0中内存的具体使用情况,review是否存在内存泄漏等(mma buffer是否在一直增加、销毁pipeline之后是否有mma buffer没有被回收)。

    3. /proc/mi_modules/mi_sys_mma/mma_heap_name0无法呈现出内存分配释放的动态信息,可使用以下命令进一步确认。当申请mma buffer 失败时,会打印当前mma heap的内存信息。可进一步分析是内存不足、泄露还是碎片化。

      echo MI_SYS_Chunk_DumpMgrPrintk > /proc/mi_modules/mi_debug/debug_func

      echo 7 > /proc/mi_modules/mi_debug/debug_level

    4. 调整pipeline,模块间尽量使用realtime,hwring等节省内存的绑定方式

    5. 提供场景图、/proc/mi_modules/mi_sys_mma/mma_heap_name0信息和kmsg打印给mi_sys owner分析给出结论

    若出现内存碎片问题,可以遵循如下步骤进行分析定位:

    1. 开启mmu,可以通过将modparam.json中的 "bEnableMmu" 字段设为true实现,设置完后需要重启或重新加载mi_sys.ko
    2. 优化应用,使用私有池,将碎片化问题限制在一定范围内。(私有池的使用请参考 MI SYS API中 MI_S32 MI_SYS_ConfigPrivateMMAPool()接口的使用说明)
    3. 增加mma 内存

    5. CMDQ 相关问题

    5.1. cmdq timeout

    当cmdq 出现timeout时,通常是因为hw 中断没有产生/某个寄存器设定不符合预期,此时会有如下的信息输出到串口:

    [CMDQ]cmdq(0) ERR: WAIT_TRIG_TIMEOUT (0x00000400)
    [CMDQ]Cmd data = 0x2000 : 0x0000 : 0x0000 : 0xFFFE
    [CMDQ]Cmd:WAIT, dbg:0, adr:000000, dat:0000, mask:fffe
    [CMDQ]Wait command timeout. Trigger_Bus Bit [0] Event [ISP_CMDQ_DONE]
    [CMDQ]dram(s, e, w, r)=(0x40000000, 0x40003ff0, 0x40000020, 0x40000020) sram(w,r)=(002,002)
    
    [CMDQ]cmdq(7) ERR: POLLEQ_TIMEOUT (0x00000200)
    [CMDQ]Cmd data = 0x3008 : 0x94F8 : 0xFF00 : 0x00FF
    [CMDQ]Cmd:POLLEQ, dbg:0, adr:1129f0, dat:ff00, mask:00ff
    [CMDQ]Poll eq command timeout.  Bank:0x1129; Offset:0x78; Value:0xff00; Mask:0x00ff
    [CMDQ]dram(s, e, w, r)=(0x4001c000, 0x4001fff0, 0x4001c030, 0x4001c030) sram(w,r)=(003,003)
    

    首先确定是哪个模块的cmdq的问题,有以下两种方式:

    5.1.1. wait trigger timeout

    当timeout类型是WAIT_TRIG_TIMEOUT时,会有Event [ISP_CMDQ_DONE],即可判断是ISP的问题

    5.1.2. other

    此外,在每次log的第一行含有cmdq id,表示发生timeout 的cmdq id。我们可以通过 cat /proc/mi_modules/mi_xx/mi_xx 查看指定模块使用的cmdq id,如下:

    ----------------------CMDQ kickoff counter-----------------------
    DevId    current_buf_size  Peak_buf_size
        0                   0              0
    each dev buf info:
                offset              length           used_flag           task_name
    

    与出问题的cmdq id比较,确定是哪个模块,最后找对应模块的sw owner,将log与运行场景交给他分析。