Files
pj_supermarket_cloud/docs/face-startup-performance.md
dzc 7c20242ad7 perf: optimize face library startup and differential sync
Stream and validate native feature loading with fast decoding and bounded SDK batches.
Reconcile authoritative department snapshots with rollback-safe metadata and file updates.
Bound downloads, isolate duplicate identifiers, and defer unchanged invalid photo versions.
Remove unused legacy face APIs and document device measurements.

Validation: 42 Flutter tests in an isolated source snapshot; native unit and device checks;
all 5,537 registered features verified byte-for-byte, plus real SDK photo searches and metadata checks.
2026-10-22 16:35:52 +08:00

6.4 KiB
Raw Permalink Blame History

人脸库启动装载优化与真机验证

验证日期:2026-10-22。设备:RK3568,Android 11。实际业务库包含 5,537 条人脸,每条特征 2,056 字节,无缺失或损坏特征。

改动

  • 原生读取改为 id > ? AND id <= ? ORDER BY id LIMIT 128,只选择装库字段,复用一个数据库连接。记录开始时的数量和最大主键,结束时校验读取数量。
  • 标准整数 JSON 数组直接解码到一次分配的 byte[],兼容 Java 有符号字节、Flutter 无符号字节;合法历史数字形式由 JsonReader 兼容解析。拒绝越界、溢出、损坏和多余尾部数据。
  • 读取和注册交替执行,注册批次采用 1,000 条,避免先在 Java 中物化整库特征再开始注册。
  • 每 150 ms 合并同阶段进度,阶段切换和结束立即发送;load 页显示实际阶段与处理数量。
  • 缺失/损坏特征逐条从原图片修复,按页提交修复事务,不再每张图片打开数据库并单独提交。
  • SDK 批次失败时清理可能的部分写入后进行二分隔离;清理失败立即中止。非法或重复搜索标识计为失败,禁止截断标识或覆盖其他用户的在库标识。
  • 虹软空库清空按幂等成功处理;结束时同时核对读取行数、成功/失败数量、SDK 数量及业务映射数量。数据库错误不返回成功的前缀结果。
  • 启动完成整库读取与修复后,收尾仅查询空特征记录,统一处理 NULL、空串、[]、null;不再把全部轻量档案传回 Dart 筛选。
  • 增加 FaceStartupPerf 脱敏汇总日志和结果 metrics,区分读库、解析、修复、引擎初始化、注册以及 Dart 激活/清理耗时。

沿用数据库 v15 和原有 JSON 特征存储格式,无数据库迁移。SDK 激活参数校验及原有人脸互斥队列继续复用。

受控 A/B 结果

同一 Debug APK、同一台设备和同一份数据,每组 3 轮,每轮重新初始化虹软引擎。旧算法仅在测试 APK 中保留用于对照;不会把旧实现带入正式包。

方案 三轮装库耗时 / ms 中位数 / ms 注册调用数
旧 SELECT *、每条 Gson、每批 100 11996 / 11418 / 11387 11418 56
优化读取/解析,每批 100 3929 / 3841 / 3871 3871 56
优化读取/解析,每批 500 3590 / 3516 / 3545 3545 12
优化读取/解析,每批 1000 3560 / 3467 / 3473 3473 6

采用 1,000 条批次后,中位数下降约 69.6%,约为旧算法的 3.29 倍速度。主要收益来自读取及解析;批次调整贡献约 0.4 秒。

最终方案三轮分段耗时:读库约 1.29–1.32 秒,解析约 1.21–1.22 秒,SDK 注册约 0.68–0.70 秒,引擎初始化约 0.25 秒;每轮只有 22 次进度事件。

独立测试不启动 Flutter UI,也不包含旧版逐条进度发送,因此与实际 App 冷启动区分记录。优化前实际 App 日志中,读库/解析约 14.29 秒,从开始查询到装库完成约 17.87 秒。原生 durationMs 不包含 Dart 中的 SDK 激活和收尾清理,完整人脸准备耗时由 startupMs 记录。

正确性与回归

  • 每组每轮均成功注册 5,537 条,失败 0 条;核对全部样本标识集合,并逐条从 SDK 取出特征与优化前 Gson 读取的字节比较。
  • 从本地四张实际照片生成 ExtractType.RECOGNIZE 查询特征,每轮检索均匹配到正确用户。SDK 区分注册特征和查询特征,不能直接使用 REGISTER 特征作查询。
  • 原生解析单元测试 3 项通过,包含随机特征及全部字节边界、历史空值、兼容数字形式、畸形/越界/长数字溢出等输入。
  • 真机独立内存 SQLite 11 项断言通过:分页边界、坏 JSON 后续行不丢失、标识溢出、修复落库、用户范围、快照上界、读取期间删除导致的不完整检测。
  • 模拟 SDK 部分写入后的失败隔离及清理失败中止 2 项断言通过。1,024 条中单个坏样本不会退化为整批逐条重试;不向实际业务库或真实 SDK 注入坏特征。
  • 最终提交的独立源码副本共 42 项 Flutter 测试通过(原有 15 项及本次新增 27 项)。
  • Flutter 静态分析无 error。原有 66 条 warning/info 之外,新增两个 Floor IN 查询产生 4 条生成代码风格提示,业务源代码没有新增提示。

最终 Release 实际 App 原生装库测得 4,315 ms,5,537 条全部成功、失败 0。启动优化阶段首次快照逐行核对已存人脸 id、sampleId、userId 和 faceModel,全部不变;数据库 v15 完整性检查正常,首次快照的订单及挂单数量不变。后续同步测试期间的完整数据核对见 face-sync-reliability.md。Release 不输出 Dart info 级控制台日志,原生 FaceStartupPerf 仍可从 adb 读取。

最新原生回归装库 3,584 ms;另有 2 项真实 SDK 元数据更新/整批拒绝断言通过,不重写特征或业务数据库。

以上验证覆盖装库、字节一致性和基于本地照片的 SDK 检索;真人摄像头活体识别与实际支付需独立验收。

复测

使用 Flutter 3.27.4、JDK 17。原生测试入口只存在于 androidTest APK,不在发布包中。

# 仓库根目录
fvm flutter test --no-pub
fvm flutter analyze --no-pub --no-fatal-infos --no-fatal-warnings

# android 目录
./gradlew :app:testDebugUnitTest :app:assembleDebug :app:assembleDebugAndroidTest
adb install -r ../build/app/outputs/apk/debug/app-debug.apk
adb install -r ../build/app/outputs/apk/androidTest/debug/app-debug-androidTest.apk

# 仅独立 SQLite 和 SDK 失败隔离检查
adb shell am instrument -w -r \
  com.example.pj_supermarket_cloud.test/io.flutter.plugins.facediscern.flutter.FaceStartupInstrumentation

# 真实数据 A/B:要求本机 SDK 已激活,所有样本已有完整特征和对应照片
adb shell am instrument -w -r -e benchmark true -e mode optimized -e batch 1000 -e rounds 3 \
  com.example.pj_supermarket_cloud.test/io.flutter.plugins.facediscern.flutter.FaceStartupInstrumentation

# 旧算法对照,或调整 batch 为 100 / 500
adb shell am instrument -w -r -e benchmark true -e mode legacy -e rounds 3 \
  com.example.pj_supermarket_cloud.test/io.flutter.plugins.facediscern.flutter.FaceStartupInstrumentation

测试不启动收银页面,不发起支付或远端人脸同步;照片只读,输出仅包含耗时、计数和通过状态。装库前需保留现有 APK 与数据库备份,使用 adb install -r 保留应用数据。