# ION 系统调试指南

## 概述

ION 系统 是 Linux 内核中用于管理设备之间内存共享的一个内存管理子系统。<br>
X5 BSP 系统中 ION 内存主要被下面四种情况使用：

- BPU 子系统
- HIFI 子系统（ DSP）
- 开发者通过 [hbmem](../../multimedia_development/3-Hbmem_index_zh_CN.html) 接口分配 ION 内存
- 多媒体系统：包含的硬件加速单元有 [VIN](../../multimedia_development/4-VIN_API_zh_CN.html)、 [ISP](../../multimedia_development/5-ISP_Tune_API_zh_CN.html)、
  [VSE](../../multimedia_development/6-VSE_API_zh_CN.html)、 [GDC](../../multimedia_development/8-GDC_index_zh_CN.html)、 [VPU](../../multimedia_development/10-MediaCodec_API_zh_CN.html)、 [OSD](../../multimedia_development/7-OSD_API_zh_CN.html)、 [GPU](../../multimedia_development/12-2DGPU_API_zh_CN.html)、 [Display](../../multimedia_development/9-Display_zh_CN.html)

### ION 内存区域

- ION 内存管理子系统使用独立的内存区域：在设备树中保留的区域，专门作为 ION 系统 , 详细见 [ION 区域调整方法 ](#id5)
- Linux 系统中通用的内存分配器是无法从 ION 内存区域分配内存的，比如内核态的 kmalloc 和 vmalloc 以及用户态的 malloc 等。
- ION 内存管理子系统为每个区域都起了不同的名字： `carveout` 、 `chunk` 、 `cma_reserved`、  `ion_cma`、  `system`  、`system_contig`。
  - X5 BSP 中主要使用 3 个 ION 区域：`cma_reserved`、`carveout`、`ion_cma`
  - `cma_reserved` 主要为多媒体系统提供内存
  - `carveout` 主要为 BPU 子系统提供内存
  - `ion_cma` 作为备用的区域，当上述两个区域没有空间时， ION 管理子系统会自动从 `ion_cma` 区域中申请内存

**注意**：关于 ION 区域名称的解释：

- ION 区域是一种动态分配内存的区域，软件中常用 heap（堆）的数据结构管理动态分配内存的区域，所以本文档和调试日志中每个 ION 区域也称作 heap 区域
- ION 是 Google 在 Android 中实现的开源的内存管理系统， ION 区域名称的解释详细见 [The Android ION memory allocator](https://lwn.net/Articles/480055/)

### ION 内存的特点

| 功能                  | 描述                                                                                           |
|-----------------------|------------------------------------------------------------------------------------------------|
| 内存管理             | ION 提供了一套通用的内存管理机制 , 支持用户态和内核态从 ION 区域申请和释放内存。|
| 连续物理内存分配       |ION 内存管理系统分配的内存是物理地址连续的，可以提供给硬件加速单元（例如 GPU、 ISP、视频解码器等）直接使用 |
| 设备间内存共享       | ION 允许不同的设备（例如 GPU、 ISP、视频解码器等）之间共享内存，通过内核实现设备间的通信与数据交换。 |
| 进程间内存共享       | 支持多个进程之间共享同一块 ION 内存区域，无需内存拷贝                                                          |
| 零拷贝               | 多个进程可以直接访问共享的内存区域，无需显式的内存拷贝，从而提高内存使用效率和系统整体性能。      |


### ION 区域分配规则

ION 管理子系统分配内存时，需要 **指定具体的 ION 区域**，因此会出现：<br>
ION 整体有空闲内存，但是由于指定的区域已经被分配完导致无法分配的情况。<br>
解决办法： ION 管理子系统支持在指定的区域无法分配内存时会自动从其他区域分配内存，分配逻辑如下：

- 当指定 cma_reserved 区域并且这个区域没有内存时： 优先选择 carveout 区域 ，其次是 ion_cma 区域
- 当指定 carveout 区域并且这个区域没有内存时： 优先选择 cma_reserved 区域 ，其次是 ion_cma 区域
- 当指定 ion_cma 区域并且这个区域没有内存时：选择 cma_reserved 区域

**注意**： ion_cma 区域存在的目的作为其他区域的备选


#### 指定具体 ION 区域的方法

- 多媒体系统和 BPU 的软件框架内部指定了首选 ION 区域，如下表所示：

| 模块      | 首选 ION 区域             |
|-------------------|-----------------------------|
| 多媒体系统       | cma_reserved 区域           |
| BPU 系统       | carveout 区域               |

**注意**：

- OSD 模块比较特殊， OSD 模块属于多媒体系统中的硬件加速单元，但是默认从 carveout 区域分配空间
- 开发者通过 [hbmem](../../multimedia_development/3-Hbmem_index_zh_CN.html) 接口分配 ION 内存时通过 Flag 参数可以指定首选 ION 区域


## ION 使用方法

### ION 区域大小调整方法

ION 区域是在设备树中预留的一段物理地址空间，这些物理地址空间属于 DDR，当设备的 DDR 容量不同时， ION 区域的预留大小也应该不同，<br>
所以 Kernel 的设备树针对不同容量的 DDR ，提供了三种情况的默认配置，分别为：

1. 1G 大小的 DDR 的默认 ION 区域配置
2. 2G 大小的 DDR 的默认 ION 区域配置
3. 大于等于 4G 大小的 DDR 的默认 ION 区域配置

上述三种情况的默认配置在启动过程中会选择一种生效，具体流程如下：

1. miniboot 启动过程中会识别到当前 DDR 的容量，并保存到寄存器中
2. uboot 启动过程中，根据 miniboot 保存到寄存器中的值，知道当前的 DDR 容量，然后解析 Kernel 设备树文件得到 当前 DDR 容量对应的 ION 内存的默认配置

以上是 ION 区域默认配置生效的流程， X5 BSP 还支持在 uboot 命令行中进行修改 ION 区域的配置。

**注意**： uboot 命令行保存的 ION 区域配置的优先级大于 Linux 设备树中配置的 ION 区域

<span id=" set_ion_size_by_linux_device_tree "/> </sapn>

#### Linux 设备树中 调整 ION 区域的方法

BSP 源码包的 kernel 目录下文件 `arch/arm64/boot/dts/hobot/x5-memory.dtsi` 中关于 ION 区域的配置如下：

```sh
/ {
	[...]
	reserved-memory {
		[...]

		/* UBoot will enable corresponding node when ddr size is confirmed */
		ion_reserved_1g: ion_reserved_1g@A4100000 {
			compatible = "ion-pool";
			reg = <0x0 0xA4100000 0x0 0x07000000>; /* 112MiB */
			status = "disabled";
		};

		ion_carveout_1g: ion_carveout_1g@AB100000 {
			compatible = "ion-carveout";
			[...]
		};

		ion_cma_1g: ion_cma_1g@B2100000 {
			compatible = "ion-cma";
			[...]
		};

		ion_reserved_2g: ion_reserved_2g@A4100000 {
			compatible = "ion-pool";
			[...]
		};

		ion_carveout_2g: ion_carveout_2g@C4100000 {
			compatible = "ion-carveout";
			[...]
		};

		ion_cma_2g: ion_cma_2g@E4100000 {
			compatible = "ion-cma";
			[...]
		};

		ion_reserved_ge4g: ion_reserved_ge4g@A4100000 {
			compatible = "ion-pool";
			[...]
		};

		ion_carveout_ge4g: ion_carveout_ge4g@E4100000 {
			compatible = "ion-carveout";
			[...]
		};

		ion_cma_ge4g: ion_cma_ge4g@124100000 {
			compatible = "ion-cma";
			[...]
		};
	};
};
```

开发者可以根据自己的 DDR 大小，按照如下表格找到不同 ION 区域对应的配置，进行修改

|DDR 容量 | ION 区域对应的设备树节点 |
| :-------| :-------------- |
|1G         | 1. cma_reserved 区域： ion_reserved_1g <br> 2. carveout 区域： ion_carveout_1g <br> 3. ion_cma 区域： ion_cma_1g|
|2G         | 1. cma_reserved 区域： ion_reserved_2g <br> 2. carveout 区域： ion_carveout_2g <br> 3. ion_cma 区域： ion_cma_2g|
| 大于等于 4G| 1. cma_reserved 区域： ion_reserved_ge4g <br> 2. carveout 区域： ion_carveout_ge4g <br> 3. ion_cma 区域： ion_cma_ge4g|

#### uboot 中调整 ION 区域的方法

参考：[uboot 动态配置内核 ION 预留内存大小功能使用说明](../driver_develop_guide/bootloader_user_guide/1-bootloader-user-guide.html#span-id-auto-set-uboot-ion-u-boot-ion)。

### ION 调试手段

X5 BSP 提供了从两个角度查看 ION 调试信息的方法：

- ION 区域的角度（内存提供者）：
  - 描述 每个 ION 区域的信息
  - 比如总共多少，使用了多少，以及每一次具体分配的内存块的信息
- client 的角度（内存使用者）：
  - client 表示使用者的身份标识，比如 进程 ID 、 VPU、 JPU 、等
  - 展示 client 整体占用的大小和每一次具体分配的内存块的信息

#### 查看各个 ION 区域的统计信息

命令如下：

- 单独查看每个 ION 区域的统计信息

``` bash
cat /sys/kernel/debug/ion/heaps/ion_cma
cat /sys/kernel/debug/ion/heaps/cma_reserved
cat /sys/kernel/debug/ion/heaps/carveout
```

- 查看所有 ION 区域的统计信息

``` bash
cat /sys/kernel/debug/ion/heaps/all_heap_info
```

其中 ion_cma、 cma_reserved、 carveout 对应了 X5 BSP 中使用的 3 个 ION 区域（其他区域未被使用）。

以 `/sys/kernel/debug/ion/heaps/cma_reserved` 为例：

```shell
root@buildroot:~# cat /sys/kernel/debug/ion/heaps/cma_reserved
-------------------------------------------------------------------------
the heap id is 6
-------------------------------------------------------------------------
-------------------------------------------------------------------------
    cma_reserved  heap total size        536870912
-------------------------------------------------------------------------
       heap name           client              pid             size
-------------------------------------------------------------------------
    cma_reserved            udevd              294          1134592
    cma_reserved            udevd              307          3145728
-------------------------------------------------------------------------
allocations (info is from last known client):
           udevd              294              gpu             4096 1
           udevd              294              gpu             4096 1
           udevd              294              gpu             4096 1
           udevd              294              gpu             8192 1
           udevd              294              gpu          1114112 1
           udevd              307              vpu          3145728 1
-------------------------------------------------------------------------
  total orphaned                0
          total           4280320
-------------------------------------------------------------------------
```

- 第一部分打印的 `heap id` 是 ION 子系统内部对各个不同类型的 ION 区域 的编号，详细请参考 BSP 源码包的文件 `kernel/include/uapi/ion.h` 内的 `enum ion_heap_type`。
- 第二部分打印的 `heap total size` 是当前 ION 区域在系统内预留的总大小（**注意**：单位为 byte， 10 进制）。
- 第三部分打印：
  - 每一列的含义可以参考标题。
  - 备注：`client` 列为 `udevd` 时，说明这部分内存分配时的用户层进程为 udevd，一般是在自动加载驱动 ko 后，驱动初始化时通过 ION 申请的内存。
- 第四部分打印展示了每个进程的每一次具体分配和分配的大小：
  - 第一列打印的是进程应用名
  - 第二列打印的是 PID（注意，这里的 PID 在每次启动都有可能不同，上列打印 **_仅供参考_** ）。
  - 第三列打印的是 X5 ION 系统自定义的模块标识符，模块标识的来源是 client 发起分配时传递的 Flag。
  - 第四列打印的是分配的大小（**注意**：单位为 byte， 10 进制）。
  - 第五列打印的是被分配的内存在内核内被引用的次数。
- 第五部分是数据总结：
  - `total orphaned` 打印的是没有 client 使用，但是没有被释放的内存大小。
  - `total` 打印的是当前 heap 总共被分配出去内存大小（单位为 byte， 10 进制）。

#### 查看从 ION 申请了内存的 client 的统计信息

X5 设备的 `/sys/kernel/debug/ion/clients/` 目录可以查看当前系统申请了 ION 内存的 client（除了 BPU 子系统）：<br>
**注意**：以下 client 的个数会根据运行程序对不同模块的使用情况而变化，仅供参考

```shell
root@buildroot:~# ls /sys/kernel/debug/ion/clients/
1114-0  display-0  dsp0-0  galcore-0  jpu-0 vio_driver_ion-0  vpu-0  vsi_cam_drv_ion-0
```

上述列出的 client 的解释如下：

| 文件名 | client | 描述 |
|---------| ----------|----|
|1114-0| 进程 ID | 使用了 ION 的进程，包含了进程用的所有模块的 ION 的信息 |
|display-0| 显示子系统 |-|
|dsp0-0| DSP  | - |
|galcore-0| GPU  | 2DGPU 和 3DGPU 使用的 ION 内存 |
|jpu-0| JPU | － |
|osd_driver_ion-0|OSD | － |
|vio_driver_ion-0| Camera 相关的硬件加速单元（除了 OSD） |Camera 相关的硬件加速单元，包含了 VIN、 ISP、 GDC、 VSE |
|vpu-0| 显示子系统 |- |
|vsi_cam_drv_ion-0| Camera 子系统后台服务 |  Camera 子系统后台服务使用的 ION 内存 |

每个 client 的具体占用则可以使用 `cat /sys/kernel/debug/ion/clients/<client name>` 来查看，以查看“ galcore-0”的 ION 占用为例：

```shell
root@buildroot:~# cat /sys/kernel/debug/ion/clients/galcore-0
       heap_name:    size_in_bytes :  handle refcount :    handle import :       buffer ptr :  buffer refcount :  buffer share id : buffer share count
    cma_reserved:             1000 :                1 :                1 :         4302dede :                2:                2 :                1

    cma_reserved:             1000 :                1 :                1 :         417b1a04 :                2:                3 :                1

    cma_reserved:             1000 :                1 :                1 :         f8c13b57 :                2:                4 :                1

    cma_reserved:             2000 :                1 :                1 :         f2a1d186 :                2:                5 :                1

    cma_reserved:           110000 :                1 :                1 :         3b5dd773 :                2:                6 :                1

-------------------------------------------------------------------------
          total            115000
-------------------------------------------------------------------------
```

- `size in bytes`: 单次申请的 ION 内存的大小：单位是 byte， 16 进制
- `buffer ptr`: 单次申请的 ION 内存的物理地址
- `total`: 当前 client 占用的 ION 区域的总体大小：单位是 byte， 16 进制


### ION 区域名称对应表

ION 区域名称、在设备树中的节点名称、 [hbmem](../../multimedia_development/3-Hbmem_index_zh_CN.html#id20) 接口中 flag 的对应关系：

| ION 区域名称  | 设备树中的节点名称 | hbmem 接口中 flag|
|--------------- | ------------------ | ----------------|
|cma_reserved| ion_reserved_xg|HB_MEM_USAGE_PRIV_HEAP_2_RESERVERD <br> HB_MEM_USAGE_PRIV_HEAP_2_RESERVED|
|carveout| ion_carveout_xg|HB_MEM_USAGE_PRIV_HEAP_RESERVERD <br> HB_MEM_USAGE_PRIV_HEAP_RESERVED|
|ion_cma| ion_cma_xg|HB_MEM_USAGE_PRIV_HEAP_DMA|

- 表头中 xg: 表示 Linux Kernel 设备树中关于 ion 保留空间节点名后缀，由于针对不同 DDR 容量，进行了不同的默认定义，所以使用 xg 来表示容量
  - 比如 ion_reserved_xg 表示的设备树节点： ion_reserved_1g、 ion_reserved_2g、 ion_reserved_ge4g

## 根据业务场景调整 ION 区域大小

X5 BSP 中 ION 区域的默认配置是按照通用场景设置的，客户可以根据自己的场景调整 ION 区域的配置，下面介绍 ION 区域的调整方法：

- 理论计算 ION 资源占用情况
- 实际运行程序，通过 ION 调试手段验证步骤一的理论值是否正确
- 根据理论值设置 ION 区域

### 理论计算 ION 资源占用情况

#### 摄像头接入相关的模块

摄像头接入相关模块包括 VIN、 ISP、 VSE、 GDC、 OSD，对 ION 资源的占用分为两个部分：

- 第一部分：[HBN 框架 ](../../multimedia_development/3-Hbmem_index_zh_CN.html)
  - 摄像头接入相关的模块是通过 `HBN 框架` 接入到客户程序中的
  - VIN、 ISP、 VSE、 GDC 都会被抽象成一个 Node 节点，多个 Node 连接成一个 Vflow
  - Node 之间数据传递的方式：上游 Node 的图像数据存储到输出队列中，下游节点从上游节点的输出队列中获取图像数据
  - Node 输出队列的存储空间是从 ION 中申请的
  - `HBN 框架` 提供了参数可以配置每个 Node 节点输出队列的缓存个数，详细见 [hbn_buf_alloc_attr_t 结构体的 buffers_num 成员 ](../../multimedia_development/1-HBN_API_zh_CN.html#hbn-buf-alloc-attr-t)

- 第二部分：后台服务程序
  - 上电后， 摄像头接入相关模块的后台服务程序会自动启动
  - 后台服务程序也会从 ION 中申请内存

##### HBN 框架

下面展示摄像头接入相关模块通过 `HBN 框架` 接入时，对 ION 内存的占用情况：<br>

其中 GDC 比较特殊，除了 GDC 的 Node 节点输出队列占用 ION 以外， GDC 的 BIN 文件也会占用，计算方法如下：<br>
`GDC BIN 文件占用 ION 资源的大小 = 4K_ALIGN( BIN 文件大小 )`

| 模块  | 占用大小                                     | 格式             |
|:------|:--------------------------------------------|:-----------------|
|VIN    |（ 4K_ALIGN（宽 * 高 * 2 ） + 4096 ）* 缓存个数 |RAW10/RAW12/RAW16 |
|ISP    |（ 4K_ALIGN（宽 * 高 * 1.5 ） + 4096 ）* 缓存个数 |NV12 |
|VSE    |（ 4K_ALIGN（宽 * 高 * 1.5 ） + 4096 ）* 缓存个数 |NV12 |
|GDC    |（ 4K_ALIGN（宽 * 高 * 1.5 ） + 4096 ）* 缓存个数 |NV12 |
|OSD    |（ 4K_ALIGN（宽 * 高 ）* 2						  |VGA8 |
|    	|（ 4K_ALIGN（宽 * 高 * 1.5 ）* 2					  |NV12 |
|    	|（ 4K_ALIGN（宽 * 高 * 3 ）* 2						|SW_VGA4 |
|    	|（ 4K_ALIGN（ 2 * 高 * sizeof(uint32_t)）* 2			|POLYGON |

- 缓存个数： Node 节点输出队列的缓存个数 , 详细见 [hbn_buf_alloc_attr_t 结构体的 buffers_num 成员 ](../../multimedia_development/1-HBN_API_zh_CN.html#hbn-buf-alloc-attr-t)
- 宽和高：当前节点处理的图像或区域 (OSD) 的分辨率的宽和高
- `4K_ALIGN`: 按照 4K 的对齐运算 ,ION 区域分配的最小单位是 4K

##### 后台服务程序

| 功能   | 占用大小 （ N: Vflow 数量） |
|:------|:--------------------------------------------|
| 固定大小 |0xAF1000 (11,472,896)|
|ISP 基础功能 |(0x38000) * N + 0x102000|
|VSE 基础功能 |0x8000 * N + 0x2000|
| 开启 3DNR 功能 |TotalSize = 宽 * 高 * 2 <br> (4K_ALIGN(TotalSize) + 4K_ALIGN(TotalSize / 4)) * N|

- `4K_ALIGN`: 按照 4K 的对齐运算
- N：标识 Vflow 的数量

#### VPU

##### H264 编码

| 功能 　| 占用大小 　　　　　　　　　　　　　　　　　　　| 描述 　　　　　　　　　　　　　　　　　　　　　　       |
|:------|:--------------------------------------------|:---------------------------------------------------|
|sei 自定义信息 |16384 * 5|-|
|customMap|262144|-|
|vui|16384|-|
|Motion Vector 运动矢量相关缓存 |4K_ALIGN(（ 64_ALIGN( 长 ) * 64_ALIGN(宽) / 32）* 2 ) + 4096|-|
|FBC Luma table buffer|4K_ALIGN(（ 256_ALIGN( 长 ) * 64_ALIGN(宽) / 32）* 2 ) + 4096|-|
|FBC Chroma table buffer|4K_ALIGN(（ 256_ALIGN( 长 /2) * 64_ALIGN(宽)/32）* 2) + 4096|-|
|Sub-sampled buffer for ME( 运动估计 )|4K_ALIGN(（ Allign32( 长 /4) * Allign4(宽/4)）* 2) + 4096|-|
| MediaCodec 软件接口的输出 buffer|4K_ALIGN（长 * 宽 * 位深 (NV12 的位深： 1.5)） * 输出缓存数量 | 举例： 1080P 的情况下 是 计算结果是 3112960 字节 |
| MediaCodec 软件接口的输入 buffer|4K_ALIGN（长 * 宽 * 位深 (NV12 的位深： 1.5)） * 输入缓存数量 | 外部内存模式不需要 |
|task buffer| 计算逻辑复杂，给出表格查询 |-|
| 重建帧和参考帧 | 计算逻辑复杂，给出表格查询 |-|

- `task buffer` 与 `重建帧和参考帧` 的计算逻辑比较复杂，计算结果只依赖图像的分辨率，可根据实际图像分辨率参考如下的表格，<br> 如果表格中没有包含指定的分辨率，可以根据如下表格进行估算

| 分辨率 | 摄像头举例 |task buffer| 重建帧和参考帧 |
|:------|:------|:------|:------|
|3840*2160|imx415|61501440|12443648 * 2|
|1920*1080|sc230|16560128|3,112,960* 2|
|1088*1280|sc132|16494592|2088960 *2|
|1600*1200|sc202|16547840|2883584 *2|
|640*480|sc035|16396288|462848* 2|


##### H265 编码

| 功能 　| 占用大小 　　　　　　　　　　　　　　　　　　　| 描述 　　　　　　　　　　　　　　　　　　　　　　       |
|:------|:--------------------------------------------|:---------------------------------------------------|
|sei 自定义信息 |16384 * 5|-|
|vui|16384|-|
|Motion Vector 运动矢量相关缓存 |4K_ALIGN(（ 64_ALIGN( 长 ) * 64_ALIGN(宽) / 32）* 2 ) + 4096|-|
|FBC Luma table buffer|4K_ALIGN(（ 256_ALIGN( 长 ) * 64_ALIGN(宽) / 32）* 2 ) + 4096|-|
|FBC Chroma table buffer|4K_ALIGN(（ 256_ALIGN( 长 /2) * 64_ALIGN(宽)/32）* 2) + 4096|-|
|Sub-sampled buffer for ME( 运动估计 )|4K_ALIGN(（ Allign32( 长 /4) * Allign4(宽/4)）* 2) + 4096|-|
| MediaCodec 软件接口的输出 buffer|4K_ALIGN（长 * 宽 * 位深 (NV12 的位深： 1.5)） * 输出缓存数量 | 举例： 1080P 的情况下 是 计算结果是 3112960 字节 |
| MediaCodec 软件接口的输入 buffer|4K_ALIGN（长 * 宽 * 位深 (NV12 的位深： 1.5)） * 输入缓存数量 | 外部内存模式不需要 |
|task buffer| 计算逻辑复杂，给出表格查询 |-|
| 重建帧和参考帧 | 计算逻辑复杂，给出表格查询 |-|

- `task buffer` 与 `重建帧和参考帧` 的计算逻辑比较复杂，计算结果只依赖图像的分辨率，可根据实际图像分辨率参考如下的表格，<br> 如果表格中没有包含指定的分辨率，可以根据如下表格进行估算

| 分辨率 | 摄像头举例 |task buffer| 重建帧和参考帧 |
|:------|:------|:------|:------|
|3840*2160|imx415|60968960|12443648  * 2|
|1920*1080|sc230|16461824 |3112960  * 2|
|1088*1280|sc132|16445440|2088960  *2|
|1600*1200|sc202|16457728|2883584  *2|
|640*480|sc035|16420864|462848 * 2|

#### BPU

| 功能 　| 占用大小 　　　　　　　　　　　　　　　　　　　| 描述 　　　　　　　　　　　　　　　　　　　　　　|
|:------|:--------------------------------------------|:--------------------------------------------|
| 固定占用 |32768 * 2| 只要使用 BPU 模块就会产生占用，并且仅占用 1 份 |
| 模型文件 |4K_ALIGN( 模型文件大小 ) +  4096  * 3| 只会占用 1 份  |
| 模型输入 Buffer 大小 | 模型输入格式决定，比如 NV12 ：<br>(4K_ALIGN( [ 模型输入宽 ] * [ 模型输入高 ] ) + <br> 4K_ALIGN( [ 模型输入宽 ] * [ 模型输入高 ] / 2 ))| 只要调用 `hbSysAllocCachedMem` 接口，就产生占用 |
| 模型输出 Buffer 大小 | 模型的输出尺寸决定，比如 yolov5 ： <br> 4K_ALIGN(output[0].AlignedByteSize) + <br>4K_ALIGN(output[1].AlignedByteSize) + <br>4K_ALIGN(output[2].AlignedByteSize) + | 只要调用 `hbSysAllocCachedMem` 接口，就产生占用 |

- 模型输入 Buffer 大小：通过接口 `hbSysAllocCachedMem` 申请，存储送入模型的图片
- 模型输出 Buffer 大小：通过接口 `hbSysAllocCachedMem` 申请，存储模型的输出结果
- `AlignedByteSize`: BPU 软件框架中结构体 `hbDNNTensorProperties` 中的成员变量 `alignedByteSize`

**注意**： BPU 占用 ION 资源还存在一些特殊情况，所以更精确的方式需要运行只跑模型的程序来测量：

- 情况 1 ：在某些模型中，运行时 BPU 的软件框架会额外从 ION 申请一个堆区域，例如 yolov5。
- 情况 2 ：有的模型的输出算子需要额外 ION 内存，比如 yolov5

### 验证理论值

正式程序或者测试程序运行后，可通过 [ION 调试手段 ](#id8) 查看各个模块的 ION 内存实际占用情况。<br>

由 [ 查看从 ION 申请了内存的 client 的统计信息 ](#ion-client) 章节知道，大部分的模块对应一个 client 节点， client 节点中可以查看这个节点占用 ION 的 TotalSize,<br>
但是有些模块比较特使， 所以分三种情况讨论：

1. 摄像头接入模块（除 OSD 和后台服务）整体作为一个 client, 无法查看每个模块的 ION 占用，所以需要借助其他方式
2. BPU 模块：没有对应的 client，需要通过其他方式
3. 其他模块： VPU、 VPU、 GPU、 OSD 等有对应的 client 节点

#### 摄像头接入模块

由于摄像头接入模块（除了 OSD），整体作为一个 client： `vio_driver_ion-0`, 所以只能看到整体占用的大小，<br>
为了查看各个模块分别占用 ION 资源的情况，需要如下步骤：

1. 在 HBN 软件接口中指定 不同的 Flag，从而 `all_heap_info` 中体现出不同的名字 。<br>
2. 查看 `all_heap_info` 节点信息并按照各个模块的名字进行过滤。

以 VIN 模块举例：（其他模块参考如下表格，替换命令中的 `cimdma`）
如下每行的第 4 列是 VIN 模块占用 ION 资源的大小（ 10 进制，单位是字节）

```sh
root@buildroot:~# cat /sys/kernel/debug/ion/heaps/all_heap_info |grep cimdma
  sunrise_camera             1070           cimdma             4096 1
  sunrise_camera             1070           cimdma          4149248 0
  sunrise_camera             1070           cimdma             4096 1
  sunrise_camera             1070           cimdma          4149248 0
  sunrise_camera             1070           cimdma             4096 1
  sunrise_camera             1070           cimdma          4149248 0
```

| 模块  | 标识   | 描述  |HBN 软件接口中指定 Flag |
|:------|:------|:------|:------|
|VIN    |cimdma |-|HB_MEM_USAGE_HW_CIM|
|ISP    |isp_yuv |-|HB_MEM_USAGE_HW_ISP|
|VSE    |other(cma_reserved) |-| 未定义，使用默认 |
|GDC    |gdc |-|HB_MEM_USAGE_HW_GDC_OUT|
|GDC BIN 文件    |gdcfb |-|HB_MEM_USAGE_HW_GDC|

- `HBN 软件接口中指定 Flag`: 详细见 [hbn_buf_alloc_attr_t 结构体的 buffers_num 成员 ](../../multimedia_development/1-HBN_API_zh_CN.html#hbn-buf-alloc-attr-t)

#### BPU 模块

如下每行的第 4 列是 BPU 模块占用 ION 资源的大小，每行的第 4 列数字的总和就是 BPU 占用 ION 资源的大小（ 10 进制，单位是字节）

```sh
root@buildroot:~# cat /sys/kernel/debug/ion/heaps/all_heap_info |grep bpu
  sunrise_camera             1070              bpu            32768 0
  sunrise_camera             1070              bpu          9486336 0
  sunrise_camera             1070              bpu          4259840 0
  sunrise_camera             1070              bpu          7864320 0
  sunrise_camera             1070              bpu             4096 0
  sunrise_camera             1070              bpu          4259840 0
  sunrise_camera             1070              bpu             4096 0
  sunrise_camera             1070              bpu             4096 0
  sunrise_camera             1070              bpu            32768 0
  sunrise_camera             1070              bpu           229376 0
  sunrise_camera             1070              bpu           229376 0
  sunrise_camera             1070              bpu           454656 0
  sunrise_camera             1070              bpu           229376 0
  sunrise_camera             1070              bpu           454656 0
  sunrise_camera             1070              bpu           454656 0
  sunrise_camera             1070              bpu           454656 0
  sunrise_camera             1070              bpu           229376 0
  sunrise_camera             1070              bpu           454656 0
  sunrise_camera             1070              bpu           229376 0
  sunrise_camera             1095              bpu           450560 0
  sunrise_camera             1095              bpu           450560 0
  sunrise_camera             1095              bpu          1802240 0
  sunrise_camera             1095              bpu          7200768 0
  sunrise_camera             1095              bpu           450560 0
  sunrise_camera             1095              bpu          1802240 0
  sunrise_camera             1095              bpu          7200768 0
  sunrise_camera             1095              bpu           450560 0
  sunrise_camera             1095              bpu          1802240 0
  sunrise_camera             1095              bpu          7200768 0
  sunrise_camera             1095              bpu          7200768 0
  sunrise_camera             1095              bpu          1802240 0
  sunrise_camera             1095              bpu           450560 0
  sunrise_camera             1095              bpu          7200768 0
  sunrise_camera             1095              bpu          1802240 0
```

#### 其他模块

如下命令，以 Display 模块为例子：
**注意**： client 节点的数字都是 16 进制的，所以 `total  5f0000` 表示 Display 占用 ION 资源的大小是： 0x5f0000 字节

```sh
root@buildroot:~# cat /sys/kernel/debug/ion/clients/display-0 |grep "total"
          total            5f0000
```

| 模块  |　client 文件名字   |
|--|----|
|VPU|vpu-0|
|JPG/MJPEG|jpu-0|
|GPU|galcore-0|
|Display|display-0|
|OSD|osd_driver_ion-0|
|DSP|dsp0-0|
| 摄像头接入模块的后台服务程序 |vsi_cam_drv_ion-0|

### 修改 ION 区域并生效

1. 快速调试的方法 : 通过 uboot 命令行配置 ，参考 [uboot 中调整 ION 区域的方法 ](#uboot-ion)
2. 正式使用的方法：修改设备树重新编译镜像，参考 [Linux 中调整 ION 区域的方法 ](#linux-ion)
