大核使用pool内存传递帧给小核之后在datafifo回调释放正常但获取出现VB_INVALID_HANDLE

Viewed 17

问题描述


自封结构体

typedef struct {
    uint64_t phys;
    uint32_t frame_len;
    uint32_t blk_size;   //  块大小 
    uint32_t handle;
} uvc_vb_msg_t;

回调释放代码如下


static void release(void *blk_ptr)
{
  int ret = 0;
  uvc_vb_msg_t *m = (uvc_vb_msg_t *)blk_ptr;
 
  if (m->phys == 0 || m->blk_size == 0 || m->frame_len == 0)
  {
    return;
  }
  k_vb_blk_handle h = (k_vb_blk_handle)m->handle;

  ret = kd_mpi_vb_inquire_user_cnt(h);
  if (ret == K_FAILED)
  {
    printf("kd_mpi_vb_inquire_user_cnt failed\n");
  }
  else
  {
    printf("kd_mpi_vb_inquire_user_cnt:%d , ", ret);
  }

  ret = kd_mpi_vb_release_block(h);
  if (ret != K_SUCCESS)
  {
    printf("release: kd_mpi_vb_release_block error=%d\n", ret);
  }
  else
  {
    printf("release %p\n", blk_ptr);
  }
}

运行打印
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000000e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000010e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000020e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000030e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000040e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000050e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000060e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000070e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000080e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000090e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000a0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000b0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000c0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000d0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000e0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000f0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000100e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000110e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000120e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000130e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000000e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000010e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000020e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000030e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000040e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000050e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000060e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000070e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000080e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000090e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000a0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000b0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000c0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000d0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000e0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x10000f0e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000100e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000110e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000120e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000130e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000000e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000010e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000020e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000030e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000040e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000050e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000060e0
kd_mpi_vb_inquire_user_cnt:1 , release 0x1000070e0
venc_consumer get vb block error
venc_consumer get vb block error
venc_consumer get vb block error
出现错误的定位就是下面这个获取内存代码,准备填充帧数据


// 取自有 VB 块(来自 1MiB 池)
    k_vb_blk_handle handle = kd_mpi_vb_get_block(g_pool_id, UVC_BLK_SZ, NULL);
    if (handle == VB_INVALID_HANDLE)
    {
      printf("%s get vb block error\n", __func__);
      kd_mpi_venc_release_stream(VENC_CH_ID, &output);
      free(output.pack);
      continue;
    }

vb的代码如下


k_u32 g_pool_id = 0;
int vb_init(void)
{
  k_vb_config config = {0};
  config.max_pool_cnt = 64;
  k_u32 i = 0;
  // VICAP raw frame output buffer
  config.comm_pool[i].blk_cnt = 24;
  config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  config.comm_pool[i].blk_size = VICAP_ALIGN_UP(ISP_WIDTH * ISP_HEIGHT * 2, 4096);
  i++;

  config.comm_pool[i].blk_cnt = 6;
  config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  config.comm_pool[i].blk_size =
      VICAP_ALIGN_UP(ISP_WIDTH * ISP_HEIGHT * 3 / 2, 4096);
  i++;

  config.comm_pool[i].blk_cnt = 12;
  config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  config.comm_pool[i].blk_size = VICAP_ALIGN_UP(ISP_WIDTH * ISP_HEIGHT * 3, 4096);
  i++;

  config.comm_pool[i].blk_cnt = 6;
  config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  config.comm_pool[i].blk_size =
      VICAP_ALIGN_UP(SENSOR_OUT_WIDTH * SENSOR_OUT_HEIGHT * 3 / 2, 4096);
  i++;

  config.comm_pool[i].blk_cnt = 12;
  config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  config.comm_pool[i].blk_size =
      VICAP_ALIGN_UP(SENSOR_OUT_WIDTH * SENSOR_OUT_HEIGHT * 3, 4096);
  i++;

  // venc
  config.comm_pool[i].blk_cnt = 10;
  config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  config.comm_pool[i].blk_size = VICAP_ALIGN_UP(ISP_WIDTH * ISP_HEIGHT, 4096);
  i++;
  // uvc
  // config.comm_pool[i].blk_cnt = 20;
  // config.comm_pool[i].mode = VB_REMAP_MODE_NOCACHE;
  // config.comm_pool[i].blk_size = VICAP_ALIGN_UP(1024 * 1024, 4096);
  // i++;

  k_s32 ret = kd_mpi_vb_set_config(&config);
  if (ret)
  {
    printf("ERROR: kd_mpi_vb_set_config failed, ret=%d\n", ret);
    return ret;
  }

  k_vb_supplement_config supplement_config = {0};
  supplement_config.supplement_config |= VB_SUPPLEMENT_JPEG_MASK;
  ret = kd_mpi_vb_set_supplement_config(&supplement_config);
  if (ret)
  {
    printf("ERROR: kd_mpi_vb_set_supplement_config failed, ret=%d\n", ret);
    return ret;
  }

  ret = kd_mpi_vb_init();
  if (ret)
  {
    printf("ERROR: kd_mpi_vb_init failed, ret=%d\n", ret);
    return ret;
  }

  k_vb_pool_config pool_config;
  memset(&pool_config, 0, sizeof(pool_config));
  pool_config.blk_cnt = 16;
  pool_config.blk_size = UVC_BLK_SZ;
  pool_config.mode = VB_REMAP_MODE_NOCACHE;
  ret = kd_mpi_vb_create_pool(&pool_config);
  if (ret == VB_INVALID_POOLID)
  {
    printf("ERROR: kd_mpi_vb_create_pool failed, ret=%ld\n", ret);
    return ret;
  }
  else
  {
    g_pool_id = ret;
  }
  return 0;
}

而且有一个疑惑是,不管我改申请的 pool_config.blk_cnt 多或者少,好像都是打印那些在循环用,我改成64就会运行的久一些,大概接近8个小时之后,还是会出现上面打印的情况

硬件板卡


01的k230开发板1G内存

软件版本


git log : commit 7e302f733311d284be255f0d81d3463b6ae6ee6d (HEAD -> main, tag: v2.0, origin/main, origin/HEAD) Author: wuwentao wuwentao@canaan-creative.com Date: Fri Sep 12 11:51:32 2025 +0800 k230 sdk release v2.0

硬件板卡


01的k230开发板1G内存

软件版本


git log : commit 7e302f733311d284be255f0d81d3463b6ae6ee6d (HEAD -> main, tag: v2.0, origin/main, origin/HEAD) Author: wuwentao wuwentao@canaan-creative.com Date: Fri Sep 12 11:51:32 2025 +0800 k230 sdk release v2.0

硬件板卡


01的k230开发板1G内存

软件版本


git log : commit 7e302f733311d284be255f0d81d3463b6ae6ee6d (HEAD -> main, tag: v2.0, origin/main, origin/HEAD) Author: wuwentao wuwentao@canaan-creative.com Date: Fri Sep 12 11:51:32 2025 +0800 k230 sdk release v2.0

硬件板卡


01的k230开发板1G内存

软件版本


git log : commit 7e302f733311d284be255f0d81d3463b6ae6ee6d (HEAD -> main, tag: v2.0, origin/main, origin/HEAD) Author: wuwentao wuwentao@canaan-creative.com Date: Fri Sep 12 11:51:32 2025 +0800 k230 sdk release v2.0

1 Answers

当 kd_mpi_vb_get_block 接口返回错误时,一个核心可能性是:该接口指定的 poolid 所对应的内存池(VB Pool)中,已无可用的视频缓存块(VB Block),所有缓存块均处于被占用状态。
出现这种情况,关键在于需进一步排查:已占用的缓存块为何未按预期正常释放,导致内存池资源无法循环复用。

看打印,占用都是1个,然后就是释放了;代码里面是kd_mpi_vb_inquire_user_cnt查询,然后调用kd_mpi_vb_release_block释放。看打印在上一轮循环的时候也能0x1000000e0到0x1000130e0释放了,所以下一轮开始应该是全空的才对。,不应该未释放了,而且也没错误打印。然后我调到64个块的时候,能跑8个小时左右才出现这个问题,说明释放应该没问题的,但是打印循环的地址也都是0x1000000e0到0x1000130e0,这会不会是有问题,按道理应该不止13了

cat /proc/umap/vb,这个命令可以查看每个内存池vb的使用情况。可以辅助你排查当前vb 是否被占用。