ohos-dev-distributed-mmi-ram-rom-measurement
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMMI RAM/ROM 影响度量
MMI RAM/ROM Impact Measurement
衡量 multimodalinput 子系统代码变更前后的 ROM(二进制体积)和 RAM(运行时内存)占用变化。
前置 skill: 编译部署、设备连接等基础设施见 。
ohos-dev-distributed-mmi-device-test-harnessMeasure changes in ROM (binary size) and RAM (runtime memory) usage of the subsystem before and after code changes.
multimodalinputPrerequisite skill: For infrastructure such as build and deployment and device connectivity, see .
ohos-dev-distributed-mmi-device-test-harnessWhen to Use
When to Use
- 提交 PR 前需要量化代码变更对二进制体积的影响
- 需要证明重构/新特性不引入内存膨胀
- 评审要求提供 RAM/ROM 数据
- You need to quantify the impact of a code change on binary size before submitting a PR
- You need to demonstrate that a refactoring or new feature does not introduce memory bloat
- A review requires RAM/ROM data
Safety and Comparability Gates
Safety and Comparability Gates
Replacing system files, remounting read-write, and rebooting a device are destructive test
operations. Do them only after explicit user approval, keep copies of every replaced library,
and restore the device to the requested final state before ending the workflow.
.so/.bakA RAM/ROM conclusion is only comparable when these conditions are recorded:
- baseline and current image/build or provenance
.so - exact libraries replaced
- whether the same functional path was executed before both captures
- whether process-level numbers are idle-vs-idle, exercised-vs-exercised, or mixed
If baseline is idle but current is post-exercise, do not present process-level PSS delta as feature
RAM cost. Use it only as context and rely on library PSS plus code-level theoretical analysis.
Replacing system files, remounting read-write, and rebooting a device are destructive test operations. Perform them only after explicit user approval, keep copies of every replaced library, and restore the device to the requested final state before ending the workflow.
.so/.bakA RAM/ROM conclusion is only comparable when the following conditions are recorded:
- The provenance of the baseline and current image/build or files
.so - The exact libraries replaced
- Whether the same functional path was executed before both captures
- Whether process-level numbers represent idle-vs-idle, exercised-vs-exercised, or mixed states
If the baseline is idle but the current measurement is post-exercise, do not present the process-level PSS delta as the feature's RAM cost. Use it only as context and rely on library PSS plus code-level theoretical analysis.
度量三支柱
Three Pillars of Measurement
本 skill 要求从三个互相佐证的维度度量 RAM 影响:
| 维度 | 方法 | 反映什么 | 局限 |
|---|---|---|---|
| ROM 段级 | | 静态映射内存(.text/.rodata/.bss) | 不反映堆分配 |
| RAM 实测 | smaps + hidumper 真机采集 | 进程实际物理内存 | 受采集条件/编译差异影响 |
| RAM 理论 | git diff 分析新增容器 + 结构体估算 | 堆分配和运行时数据结构 | 人工估算,依赖正确的结构体大小分析 |
三个维度必须同时完成,互相交叉验证。仅做段级估算会遗漏堆分配;仅做实测会受噪声影响;仅做理论分析无法确认实际表现。
This skill requires RAM impact to be measured from three mutually corroborating dimensions:
| Dimension | Method | What It Reflects | Limitations |
|---|---|---|---|
| ROM section-level | | Statically mapped memory ( | Does not reflect heap allocations |
| RAM measured | smaps + on-device hidumper collection | Actual physical memory used by a process | Affected by collection conditions and build differences |
| RAM theoretical | git diff analysis of new containers + structure-size estimation | Heap allocations and runtime data structures | Manual estimation that depends on correct structure-size analysis |
All three dimensionsmust be completed and cross-validated. Section-level estimation alone misses heap allocations; measurements alone are affected by noise; theoretical analysis alone cannot confirm actual behavior.
度量目标库和进程范围
Target Libraries and Process Scope
先根据代码变更确定影响面,不要默认只看服务端进程。至少检查改动是否触达以下库:
| 库 | 角色 | RAM 分析范围 |
|---|---|---|
| 服务端主逻辑 | |
| 服务端公共 | |
| 工具库 | 所有加载该库的目标进程 |
| 客户端 API/代理 | 触发该 API 的客户端进程,不能用服务端进程 PSS 代表 |
规则:
- ROM 分析应覆盖所有受影响的 libmmi ,包括
.so。libmmi-client.z.so - RAM 分析必须按实际加载进程归属。通常不在
libmmi-client.z.so服务端进程中加载;如果客户端 API、proxy、NAPI 或测试二进制路径受影响,需要选择一个会加载multimodalinput的客户端进程执行功能路径并采集该进程的 smaps/hidumper 数据。libmmi-client.z.so - 如果改动只影响服务端内部路径,可以说明 client so 未加载到服务端进程,但仍要用代码 diff、符号
或段级数据确认 是否真的无变化或不参与本次 RAM 结论。
libmmi-client.z.so - 最终报告要列出“库 → 进程 → 是否执行功能路径 → 是否纳入 RAM 结论”的映射,避免把服务端 PSS 误当成全量 MMI RAM 成本。
First determine the impact scope from the code changes. Do not assume that only the server process needs to be inspected. At minimum, check whether the changes affect the following libraries:
| Library | Role | RAM Analysis Scope |
|---|---|---|
| Main server logic | |
| Shared server code | |
| Utility library | Every target process that loads the library |
| Client API/proxy | The client process that invokes the API; server-process PSS is not a valid substitute |
Rules:
- ROM analysis must cover every affected libmmi , including
.so.libmmi-client.z.so - RAM analysis must follow the actual process that loads each library. is generally not loaded in the
libmmi-client.z.soserver process. If the client API, proxy, NAPI, or test-binary path is affected, select a client process that loadsmultimodalinput, execute the functional path in that process, and collect its smaps/hidumper data.libmmi-client.z.so - If the changes affect only an internal server path, you may state that the client is not loaded in the server process. However, you must still use the code diff, symbols, or section-level data to confirm that
.sois genuinely unchanged or does not participate in the RAM conclusion.libmmi-client.z.so - The final report must include a “library → process → functional path executed → included in RAM conclusion” mapping to avoid presenting server-process PSS as the total MMI RAM cost.
ROM 度量方法
ROM Measurement Methods
1. 文件级对比(快速)
1. File-Level Comparison (Quick)
bash
BUILD_OUT="code/out/rk3568/multimodalinput/input"
ls -la $BUILD_OUT/libmmi-*.z.sobash
BUILD_OUT="code/out/rk3568/multimodalinput/input"
ls -la $BUILD_OUT/libmmi-*.z.so2. 段级对比(精确,推荐)
2. Section-Level Comparison (Precise, Recommended)
使用 分析关键段:
readelf -Sbash
readelf -S libmmi-server.z.so | grep -E '\.text|\.rodata|\.data|\.bss'| 段 | 含义 | 影响 |
|---|---|---|
| 可执行代码 | 直接影响 ROM;映射为 shared clean 影响 RAM PSS |
| 只读数据(字符串常量等) | 影响 ROM 和 shared clean PSS |
| 已初始化全局变量 | 影响 ROM 和 private dirty |
| 零初始化全局变量 | 不影响 ROM;影响 anonymous RAM |
| 重定位后只读 | 影响 ROM |
Use to analyze the key sections:
readelf -Sbash
readelf -S libmmi-server.z.so | grep -E '\.text|\.rodata|\.data|\.bss'| Section | Meaning | Impact |
|---|---|---|
| Executable code | Directly affects ROM; mapped as shared clean and affects RAM PSS |
| Read-only data, such as string constants | Affects ROM and shared clean PSS |
| Initialized global variables | Affects ROM and private dirty memory |
| Zero-initialized global variables | Does not affect ROM; affects anonymous RAM |
| Read-only after relocation | Affects ROM |
3. 基线获取策略
3. Baseline Acquisition Strategy
方案 A:设备 .bak 文件(推荐)
部署修改版 .so 前,先备份原始 .so:
bash
$HDC shell "cp /system/lib/libmmi-server.z.so /data/local/tmp/libmmi-server.z.so.bak"Option A: Device Files (Recommended)
.bakBefore deploying the modified files, back up the original files:
.sobash
$HDC shell "cp /system/lib/libmmi-server.z.so /data/local/tmp/libmmi-server.z.so.bak"部署新 .so...
Deploy the new .so...
之后拉取基线
Then pull the baseline
$HDC file recv /data/local/tmp/libmmi-server.z.so.bak ./libmmi-server.z.so.bak
**方案 B:CI 基线构建**
从 CI 每日构建镜像中提取同版本 .so 作为基线。$HDC file recv /data/local/tmp/libmmi-server.z.so.bak ./libmmi-server.z.so.bak
**Option B: CI Baseline Build**
Extract the `.so` files from the same version in the daily CI-built image as the baseline.RAM 度量方法
RAM Measurement Methods
1. 找到进程 PID
1. Find the Process PID
bash
$HDC shell "pidof multimodalinput"注意 PID 稳定性:multimodalinput 是系统服务,可能被 watchdog 重启导致 PID 变化。在多条 hdc 命令之间 PID 可能不同。解决方案:使用命令替换在单次 hdc shell 调用中完成 PID 查找和数据采集:
bash
$HDC shell "cat /proc/\$(pidof multimodalinput)/smaps_rollup"bash
$HDC shell "pidof multimodalinput"PID stability: is a system service and may be restarted by the watchdog, causing its PID to change. The PID may differ between multiple HDC commands. Solution: Use command substitution to find the PID and collect the data within a single HDC shell invocation:
multimodalinputbash
$HDC shell "cat /proc/\$(pidof multimodalinput)/smaps_rollup"2. smaps_rollup(进程级汇总)
2. smaps_rollup (Process-Level Summary)
bash
$HDC shell "cat /proc/\$(pidof multimodalinput)/smaps_rollup"关键字段:
- Pss: 按共享比例分摊后的实际物理内存(最能反映真实占用)
- Rss: 驻留物理内存(包含共享页全量)
- Size: 虚拟地址空间大小
bash
$HDC shell "cat /proc/\$(pidof multimodalinput)/smaps_rollup"Key fields:
- Pss: Actual physical memory after shared pages are proportionally allocated; it best reflects real usage
- Rss: Resident physical memory, including the full amount of shared pages
- Size: Virtual address-space size
3. smaps per-library PSS(重要)
3. smaps Per-Library PSS (Important)
bash
$HDC shell "cat /proc/\$(pidof multimodalinput)/smaps" > smaps.txt解析脚本和注意事项见 。关键要求是每个 mapping header 都要重置当前库名,避免把 anonymous PSS 错归到上一个 。
references/smaps-pss-attribution.md.sobash
$HDC shell "cat /proc/\$(pidof multimodalinput)/smaps" > smaps.txtSee for the parsing script and precautions. A key requirement is to reset the current library name at every mapping header so that anonymous PSS is not incorrectly attributed to the preceding .
references/smaps-pss-attribution.md.so4. hidumper --mem(系统级)
4. hidumper --mem (System-Level)
bash
$HDC shell "hidumper --mem \$(pidof multimodalinput)"输出包含:native heap、.so mmap PSS、total PSS 等分类。
注意:hidumper 输出可能很长,通过 hdc shell 可能被截断。可重定向到文件后拉取:
bash
$HDC shell "hidumper --mem \$(pidof multimodalinput) > /data/local/tmp/hidumper_mem.txt"
$HDC file recv /data/local/tmp/hidumper_mem.txt ./hidumper_mem.txtbash
$HDC shell "hidumper --mem \$(pidof multimodalinput)"The output includes categories such as native heap, mmap PSS, and total PSS.
.soNote: The hidumper output may be very long and can be truncated when passed through HDC shell. Redirect it to a file and then pull the file:
bash
$HDC shell "hidumper --mem \$(pidof multimodalinput) > /data/local/tmp/hidumper_mem.txt"
$HDC file recv /data/local/tmp/hidumper_mem.txt ./hidumper_mem.txt5. RAM 增量归因(必须)
5. RAM Delta Attribution (Mandatory)
每一个 RAM 增长结论都必须回答“增长来自哪里”。不能只报告 total PSS 或
进程 PSS 差值。至少把增长拆成以下来源并给出证据:
multimodalinput| 来源 | 证据 | 处理要求 |
|---|---|---|
新增/变化的 | baseline/current smaps 中的 mapped | 列出每个 |
| libmmi 代码段变化 | | 单独列出 libmmi 各库 PSS 增量和对应 section 差异 |
| native heap 增长 | | 对应到新增容器、对象、缓存、RS 资源或生命周期状态 |
| anonymous/file PSS 增长 | smaps_rollup | 说明是否来自堆、匿名映射、文件映射、测试框架或系统状态 |
| 测试环境/框架噪声 | 新增加载的测试二进制依赖、input-test 框架等 | 与目标特性分开,不得直接归因给代码变更 |
| 未归因残差 | total delta - 已解释 delta | 单独列出;残差过大时结论只能标记为“不完整归因” |
推荐从 smaps 中按完整路径聚合所有 PSS,而不是只匹配 ;参考脚本见 。
.solibmmireferences/smaps-pss-attribution.md对 baseline/current 两份结果做 outer join,生成“新增/变化的已加载 ”表:
.so| 进程 | | 基线 PSS(kB) | 当前 PSS(kB) | 差值(kB) | 是否新增加载 | 归因 |
|---|---|---|---|---|---|---|
| multimodalinput | /system/lib/libmmi-server.z.so | X | Y | +/-Z | no | libmmi server 代码段变化 |
| multimodalinput | /system/lib/libxxx.z.so | 0 | Y | +Y | yes | 功能路径触发 / 测试框架 / 环境噪声 |
如果内存增长主要来自加载了新的 ,报告必须列出这些 的名称、路径、
PSS 增量和触发原因;不能只写“.so mmap PSS 增长”。如果无法证明某个新加载库由目标
特性触发,应归入“环境/测试框架差异”或“未归因”,不要归入目标特性成本。
.so.soEvery RAM-growth conclusion must answer “where did the growth come from?” It is not sufficient to report only the total PSS or the delta in the process PSS. At minimum, break the growth down into the following sources and provide evidence:
multimodalinput| Source | Evidence | Processing Requirement |
|---|---|---|
New or changed | Mapped | List each |
| Changes to libmmi code sections | | Separately list the PSS delta of each libmmi library and the corresponding section differences |
| Native heap growth | | Correlate it with new containers, objects, caches, RS resources, or lifecycle state |
| Anonymous/file PSS growth | smaps_rollup | Determine whether it comes from the heap, anonymous mappings, file mappings, the test framework, or system state |
| Test environment/framework noise | Newly loaded test-binary dependencies and input-test framework | Keep them separate from the target feature; do not attribute them directly to the code change |
| Unattributed residual | total delta - explained delta | List separately; if the residual is too large, the conclusion must be marked as “incomplete attribution” |
It is recommended to aggregate PSS for all files from smaps using their complete paths rather than matching only . See for a reference script.
.solibmmireferences/smaps-pss-attribution.mdPerform an outer join on the baseline/current results to generate a table of newly loaded or changed files:
.so| Process | | Baseline PSS (kB) | Current PSS (kB) | Delta (kB) | Newly Loaded | Attribution |
|---|---|---|---|---|---|---|
| multimodalinput | /system/lib/libmmi-server.z.so | X | Y | +/-Z | no | libmmi server code-section changes |
| multimodalinput | /system/lib/libxxx.z.so | 0 | Y | +Y | yes | Functional path trigger / test framework / environment noise |
If memory growth mainly comes from newly loaded files, the report must list each library's name, path, PSS delta, and trigger. It is not sufficient to state only that “.so mmap PSS increased.” If a newly loaded library cannot be proven to have been triggered by the target feature, classify it as an “environment/test-framework difference” or “unattributed,” not as the target feature's cost.
.so6. 基线 RAM 获取
6. Baseline RAM Acquisition
精确方法:临时恢复 .bak .so → 重启 → 采集 → 恢复修改版 .so
bash
undefinedPrecise method: Temporarily restore the files → reboot → collect data → restore the modified files
.bak.so.sobash
undefined1. 备份当前修改版
1. Back up the current modified files
$HDC shell "mount -o rw,remount /" # RK3568 根文件系统在 /,不是 /system
$HDC shell "cp /system/lib/libmmi-server.z.so /data/local/tmp/libmmi-server.z.so.new"
$HDC shell "mount -o rw,remount /" # The RK3568 root filesystem is mounted at /, not /system
$HDC shell "cp /system/lib/libmmi-server.z.so /data/local/tmp/libmmi-server.z.so.new"
对 libmmi-server-common.z.so, libmmi-util.z.so 同样操作
Do the same for libmmi-server-common.z.so and libmmi-util.z.so
2. 恢复基线
2. Restore the baseline
$HDC shell "cp /data/local/tmp/libmmi-server.z.so.bak /system/lib/libmmi-server.z.so"
$HDC shell "cp /data/local/tmp/libmmi-server.z.so.bak /system/lib/libmmi-server.z.so"
对每个库同样恢复 .bak
Restore the .bak file for each library in the same way
$HDC shell "reboot"
$HDC shell "reboot"
等待重启 (~60s)...
Wait for the reboot (~60s)...
3. 采集基线 RAM
3. Collect baseline RAM data
$HDC shell "cat /proc/$(pidof multimodalinput)/smaps_rollup"
$HDC shell "cat /proc/$(pidof multimodalinput)/smaps" > smaps_baseline.txt
$HDC shell "hidumper --mem $(pidof multimodalinput) > /data/local/tmp/hidumper_baseline.txt"
$HDC shell "cat /proc/$(pidof multimodalinput)/smaps_rollup"
$HDC shell "cat /proc/$(pidof multimodalinput)/smaps" > smaps_baseline.txt
$HDC shell "hidumper --mem $(pidof multimodalinput) > /data/local/tmp/hidumper_baseline.txt"
4. 恢复修改版
4. Restore the modified files
$HDC shell "mount -o rw,remount /"
$HDC shell "cp /data/local/tmp/libmmi-server.z.so.new /system/lib/libmmi-server.z.so"
$HDC shell "mount -o rw,remount /"
$HDC shell "cp /data/local/tmp/libmmi-server.z.so.new /system/lib/libmmi-server.z.so"
对每个库同样恢复 .new
Restore the .new file for each library in the same way
$HDC shell "reboot"
> **RK3568 mount 注意**:根文件系统挂载在 `/`,不是 `/system`。`mount -o rw,remount /system` 会报 "not in /proc/mounts" 错误。正确命令是 `mount -o rw,remount /`。
**估算方法**(不需要重启):
基于段级分析推算 RAM 变化:
- `.text` + `.rodata` 差值 → 影响 shared clean PSS
- `.bss` 差值 → 影响 anonymous 内存
- `.data` 差值 → 影响 private dirty
当段差值很小(< 1%)且 `.bss` 无变化时,可以直接用估算方法而无需重启。$HDC shell "reboot"
> **RK3568 mount note**: The root filesystem is mounted at `/`, not `/system`. Running `mount -o rw,remount /system` produces a “not in /proc/mounts” error. The correct command is `mount -o rw,remount /`.
**Estimation method** (no reboot required):
Estimate RAM changes based on section-level analysis:
- `.text` + `.rodata` delta → affects shared clean PSS
- `.bss` delta → affects anonymous memory
- `.data` delta → affects private dirty memory
When the section delta is very small (< 1%) and `.bss` is unchanged, the estimation method can be used directly without rebooting.7. 采集前必须执行功能路径
7. The Functional Path Must Be Executed Before Collection
关键约束:仅部署 .so 并重启是不够的。如果变更引入了懒分配(lazy allocation)的数据结构,必须在采集前执行完整的功能路径,确保所有运行时状态被实际分配:
部署 .so → 重启 → 等待系统稳定 (30s) → 执行功能路径 → 等待稳定 (5s) → 采集功能路径按变更内容定义,不要固定成某一个特性用例。通用模板:
- 初始化变更依赖的系统状态(如 display、window、device、session、permission)。
- 调用新增或修改的 public API、IPC、server handler、callback 或事件路径。
- 触发懒分配和缓存路径(如首次事件、重复事件、边界设备、窗口、显示组)。
- 覆盖清理路径(解绑、销毁、断连、窗口删除、服务重启前后状态)。
- 记录实际执行的步骤,并说明哪些受影响库和进程被该路径覆盖。
例如 display group 绑定可以用 、、
和事件注入触发;其他特性必须替换成自己的最小完备功能路径。
UpdateDisplayInfoUpdateWindowInfoBindDeviceToDisplayGroupByDisplay不执行功能路径的 RAM 采集会低估实际内存占用,因为懒分配的容器仍为空。
Critical constraint: Deploying the files and rebooting is not sufficient. If a change introduces a lazily allocated data structure, the complete functional path must be executed before collection to ensure that all runtime state has actually been allocated:
.soDeploy .so → Reboot → Wait for system stability (30s) → Execute functional path → Wait for stability (5s) → Collect dataDefine the functional path according to the change rather than fixing it to one feature test case. A general template is:
- Initialize the system state required by the change, such as display, window, device, session, and permission state.
- Invoke the new or modified public API, IPC, server handler, callback, or event path.
- Trigger lazy-allocation and cache paths, such as the first event, repeated events, boundary devices, windows, and display groups.
- Cover cleanup paths, including unbinding, destruction, disconnection, window deletion, and state before and after a service restart.
- Record the steps actually executed and explain which affected libraries and processes are covered by the path.
For example, display-group binding can be triggered through , , , and event injection. Other features must use their own minimal complete functional path.
UpdateDisplayInfoUpdateWindowInfoBindDeviceToDisplayGroupByDisplayCollecting RAM data without executing the functional path willunderestimate actual memory usage because lazily allocated containers will still be empty.
代码理论分析方法(第三支柱)
Code-Level Theoretical Analysis Method (Third Pillar)
段级估算只能反映静态映射内存,无法反映堆分配(new/malloc)。对于引入新数据结构的特性变更,必须分析代码 diff 中的新增容器和对象。
详细估算规则见 。主流程只要求输出:
references/theoretical-ram-estimation.md- 新增容器、对象、缓存和 RS 资源清单。
- 每类对象的典型场景和上界场景估算。
- 分配时机、清理路径和泄漏风险。
- 理论估算与实测 libmmi PSS/native heap/Pss_Anon 的交叉验证结论。
Section-level estimation can reflect only statically mapped memory and cannot reflect heap allocations (/). For feature changes that introduce new data structures, youmust analyze new containers and objects in the code diff.
newmallocSee for detailed estimation rules. The main process only needs to produce the following:
references/theoretical-ram-estimation.md- A list of new containers, objects, caches, and RS resources
- Typical-scenario and upper-bound-scenario estimates for each object type
- Allocation timing, cleanup paths, and leak risks
- A cross-validation conclusion comparing theoretical estimates with measured libmmi PSS, native heap, and Pss_Anon
输出报告模板
Output Report Template
markdown
undefinedmarkdown
undefinedROM 影响
ROM Impact
文件级对比
File-Level Comparison
| 库 | 基线(bytes) | 当前(bytes) | 差值 | 比例 |
|---|---|---|---|---|
| libmmi-server.z.so | X | Y | +/-Z | +/-N% |
| ... | ||||
| 合计 |
| Library | Baseline (bytes) | Current (bytes) | Delta | Percentage |
|---|---|---|---|---|
| libmmi-server.z.so | X | Y | +/-Z | +/-N% |
| ... | ||||
| Total |
libmmi-server.z.so 段级分析
Section-Level Analysis of libmmi-server.z.so
| 段 | 基线 | 当前 | 差值 |
|---|---|---|---|
| .text | X | Y | +/-Z |
| .rodata | |||
| .data | |||
| .bss |
| Section | Baseline | Current | Delta |
|---|---|---|---|
| .text | X | Y | +/-Z |
| .rodata | |||
| .data | |||
| .bss |
影响范围映射
Impact Scope Mapping
| 库 | 受影响代码路径 | 目标进程 | 是否采集 RAM | 说明 |
|---|---|---|---|---|
| libmmi-server.z.so | server handler / event path | multimodalinput | yes/no | |
| libmmi-client.z.so | client API / proxy / NAPI | <client-process-or-test-binary> | yes/no |
| Library | Affected Code Path | Target Process | RAM Collected | Description |
|---|---|---|---|---|
| libmmi-server.z.so | server handler / event path | multimodalinput | yes/no | |
| libmmi-client.z.so | client API / proxy / NAPI | <client-process-or-test-binary> | yes/no |
RAM 影响
RAM Impact
RAM 增长原因归因
RAM Growth Attribution
进程级增量拆解
Process-Level Delta Breakdown
| 指标/类别 | 基线(kB) | 当前(kB) | 差值(kB) | 证据来源 | 归因 |
|---|---|---|---|---|---|
| total PSS | X | Y | +/-Z | smaps_rollup / hidumper | 汇总,仅作入口 |
| .so mmap PSS | X | Y | +/-Z | hidumper + smaps | 见“已加载 .so 增量”表 |
| native heap | X | Y | +/-Z | hidumper | 见“heap/anonymous 增量”表 |
| Pss_Anon | X | Y | +/-Z | smaps_rollup | heap/anonymous/运行时状态 |
| Pss_File | X | Y | +/-Z | smaps_rollup | 文件映射或加载库变化 |
| Metric/Category | Baseline (kB) | Current (kB) | Delta (kB) | Evidence Source | Attribution |
|---|---|---|---|---|---|
| total PSS | X | Y | +/-Z | smaps_rollup / hidumper | Summary only; entry point |
| .so mmap PSS | X | Y | +/-Z | hidumper + aggregated smaps | See “Loaded .so Delta” table |
| native heap | X | Y | +/-Z | hidumper | See “Heap/Anonymous Delta” table |
| Pss_Anon | X | Y | +/-Z | smaps_rollup | Heap/anonymous/runtime state |
| Pss_File | X | Y | +/-Z | smaps_rollup | File mappings or changes in loaded libraries |
已加载 .so 增量
Loaded .so Delta
| 进程 | | 基线 PSS(kB) | 当前 PSS(kB) | 差值(kB) | 是否新增加载 | 触发路径/归因 |
|---|---|---|---|---|---|---|
| multimodalinput | /system/lib/libmmi-server.z.so | X | Y | +/-Z | no | 目标 libmmi 代码变化 |
| <process> | /system/lib/libxxx.z.so | 0 | Y | +Y | yes | 功能路径触发 / 测试框架 / 环境噪声 |
| Process | | Baseline PSS (kB) | Current PSS (kB) | Delta (kB) | Newly Loaded | Trigger Path/Attribution |
|---|---|---|---|---|---|---|
| multimodalinput | /system/lib/libmmi-server.z.so | X | Y | +/-Z | no | Target libmmi code changes |
| <process> | /system/lib/libxxx.z.so | 0 | Y | +Y | yes | Functional path trigger / test framework / environment noise |
libmmi PSS 增量
libmmi PSS Delta
| 库 | 基线 PSS (kB) | 当前 PSS (kB) | 差值 | section 证据 | 归因 |
|---|---|---|---|---|---|
| libmmi-server.z.so | X | Y | +/-Z | .text/.rodata/.data/.bss 差异 | server 代码路径 |
| libmmi-client.z.so | X | Y | +/-Z | .text/.rodata/.data/.bss 差异 | client API/proxy 路径 |
| Library | Baseline PSS (kB) | Current PSS (kB) | Delta | Section Evidence | Attribution |
|---|---|---|---|---|---|
| libmmi-server.z.so | X | Y | +/-Z | .text/.rodata/.data/.bss differences | Server code path |
| libmmi-client.z.so | X | Y | +/-Z | .text/.rodata/.data/.bss differences | Client API/proxy path |
heap/anonymous 增量
Heap/Anonymous Delta
| 增长项 | 估算增量 | 实测对应指标 | 代码证据 | 分配/释放路径 | 结论 |
|---|---|---|---|---|---|
| 新增 map/vector/cache | X KB | native heap / Pss_Anon | 文件:行号或 diff 摘要 | 创建/清理函数 | 目标特性成本 |
| 测试框架对象 | X KB | native heap / Pss_Anon | 测试入口或依赖 | 测试进程生命周期 | 环境差异 |
| Growth Item | Estimated Delta | Corresponding Measured Metric | Code Evidence | Allocation/Release Path | Conclusion |
|---|---|---|---|---|---|
| New map/vector/cache | X KB | native heap / Pss_Anon | File:line number or diff summary | Creation/cleanup function | Target feature cost |
| Test framework objects | X KB | native heap / Pss_Anon | Test entry point or dependency | Test process lifecycle | Environment difference |
未归因残差
Unattributed Residual
| total PSS 差值 | 已解释 .so 差值 | 已解释 heap/anon 差值 | 未归因残差 | 处理 |
|---|---|---|---|---|
| +X kB | +Y kB | +Z kB | +N kB | N 过大时标记结论不完整,并继续补采 smaps/hidumper/功能路径证据 |
| Total PSS Delta | Explained .so Delta | Explained Heap/Anon Delta | Unattributed Residual | Handling |
|---|---|---|---|---|
| +X kB | +Y kB | +Z kB | +N kB | If N is too large, mark the conclusion as incomplete and continue collecting smaps/hidumper/functional-path evidence |
实测对比(libmmi 库 PSS)
Measured Comparison (libmmi Library PSS)
| 库 | 基线 PSS (kB) | 修改版 PSS (kB) | 差值 | 归因 |
|---|---|---|---|---|
| libmmi-server.z.so | X | Y | +/-Z | section/code path evidence |
| ... |
| Library | Baseline PSS (kB) | Modified PSS (kB) | Delta | Attribution |
|---|---|---|---|---|
| libmmi-server.z.so | X | Y | +/-Z | section/code path evidence |
| ... |
理论分析
Theoretical Analysis
| 场景 | 当前实现 | 后续/完整实现(如适用) |
|---|---|---|
| 不使用路径 | ~X B | ~X B |
| 典型功能路径 | ~X KB | ~X KB |
| 极端上界 | ~X KB/MB | ~X KB/MB |
| Scenario | Current Implementation | Future/Complete Implementation, if applicable |
|---|---|---|
| Unused path | ~X B | ~X B |
| Typical functional path | ~X KB | ~X KB |
| Extreme upper bound | ~X KB/MB | ~X KB/MB |
实测 vs 理论对照
Measured vs. Theoretical Comparison
[说明两者是否一致,差异原因]
[Explain whether the two are consistent and the reasons for any differences.]
结论
Conclusion
ROM: +/-X bytes (+/-N%)
RAM: 服务端进程 PSS +/-X kB;客户端进程 PSS +/-Y kB(如适用);理论典型场景 ~Z KB
undefinedROM: +/-X bytes (+/-N%)
RAM: server-process PSS +/-X kB; client-process PSS +/-Y kB (if applicable); theoretical typical scenario ~Z KB
undefinedCommon Mistakes
Common Mistakes
| 错误 | 后果 | 修复 |
|---|---|---|
用 | 文件大小包含 ELF 头、符号表等不映射到内存的部分 | 用 readelf 段级分析 |
| 忽略 .bss 段 | .bss 不占 ROM 但影响 anonymous RAM | 单独检查 .bss |
| 拿 RSS 做进程间对比 | RSS 包含共享页全量,被多次计算 | 用 PSS |
| 对比不同版本系统的 RAM 数据 | 系统库版本差异导致噪声 | 确保只替换目标 .so,系统基线一致 |
| client so 不在服务端进程加载,RAM 结论缺失 | 选择加载 client so 的客户端进程或测试二进制单独采集 |
| 重启后不执行功能路径就采集 | 懒分配的数据结构未实际分配,RAM 被低估 | 采集前必须执行完整功能路径触发所有状态分配 |
| 只做段级估算不做理论分析 | 段级估算不反映堆分配(new/malloc),遗漏运行时数据结构 | 结合 diff 中的新增容器做理论内存估算 |
| 只做理论分析不做实测 | 理论估算可能遗漏/高估,无法确认实际表现 | 三支柱(段级 + 实测 + 理论)交叉验证 |
| 只报 total PSS 或 .so mmap PSS 增长 | 无法判断增长来自哪个库、堆对象还是测试环境 | 必须列出进程级分类、每个已加载 |
| 无法判断是否由目标特性加载库导致 | 对 baseline/current 的完整 |
把测试框架额外加载的 | 夸大特性 RAM 成本 | 未证明由目标功能触发的 |
| smaps 解析器不重置 current_lib | anonymous mapping 的 PSS 被错误归入上一个 libmmi 库,严重高估 | 每个 mapping header 行必须重置 current_lib |
| PID 在多条 hdc 命令间变化 | 读取了不同进程的 smaps | 使用 |
| RK3568 根文件系统在 /,报 "not in /proc/mounts" | 使用 |
| 忽略 Parcelable/RefBase 继承 | 低估含 RefCounter 堆分配的对象大小 | 分析完整继承链,包含 vtable 和 RefCounter |
| 忽略 RS SurfaceNode/BufferQueue | 遗漏最大的单项内存开销(每 group 50-200 KB) | 分析 RS 资源创建路径,区分 nullptr vs 实际创建 |
| 理论分析只看 sizeof 不看堆分配 | 遗漏 std::string 长字符串、vector 元素、map 节点的堆分配 | 分析每个字段的实际内存布局 |
| Mistake | Consequence | Fix |
|---|---|---|
Using | File size includes the ELF header, symbol table, and other parts that are not mapped into memory | Use readelf section-level analysis |
Ignoring the | | Check |
| Using RSS for cross-process comparisons | RSS includes the full amount of shared pages and causes double counting | Use PSS |
| Comparing RAM data from different system versions | Differences in system library versions introduce noise | Ensure that only the target |
Inspecting | The client | Select a client process or test binary that loads the client |
| Collecting data after reboot without executing the functional path | Lazily allocated data structures are not actually allocated, underestimating RAM | Always execute the complete functional path before collection to trigger all state allocations |
| Performing only section-level estimation without theoretical analysis | Section-level estimation does not reflect heap allocations ( | Combine it with theoretical memory estimation of new containers in the diff |
| Performing only theoretical analysis without measurement | Theoretical estimates may miss or overestimate actual behavior and cannot confirm actual performance | Cross-validate the three pillars: section-level analysis, measurement, and theoretical analysis |
Reporting only total PSS or | It is impossible to determine whether the growth came from a library, heap objects, or the test environment | Include process-level categories, the PSS delta for every loaded |
Observing | It is impossible to determine whether the target feature caused the libraries to be loaded | Perform an outer join on the complete baseline/current |
Attributing | This overstates the feature's RAM cost | Classify |
The smaps parser does not reset | Anonymous mapping PSS is incorrectly attributed to the preceding libmmi library, severely overestimating its usage | Reset |
| The PID changes between multiple HDC commands | Data is read from different processes | Use |
| The RK3568 root filesystem is mounted at | Use |
| Ignoring Parcelable/RefBase inheritance | This underestimates the heap allocation size of objects containing a RefCounter | Analyze the complete inheritance chain, including the vtable and RefCounter |
| Ignoring RS SurfaceNode/BufferQueue | This misses the largest individual memory cost, at 50–200 KB per group | Analyze the RS resource creation path and distinguish |
Considering only | This misses heap allocations for long | Analyze the actual memory layout of every field |