Ente 移动端 ML 调度验证报告:DVFS 与线程调度如何让 Pixel 8 的 Rust 预处理慢 2.8 倍,以及如何修复
2026/9/12 15:48:32 网站建设 项目流程

Ente 移动端 ML 调度验证报告:DVFS 与线程调度如何让 Pixel 8 的 Rust 预处理慢 2.8 倍,以及如何修复

【免费下载链接】ente💚 End-to-end encrypted cloud for everything.项目地址: https://gitcode.com/GitHub_Trending/en/ente

导读

Ente 的移动端 ML 索引管线(人脸检测、CLIP 图像嵌入、人脸特征提取)在 Android(ONNX Runtime WebGPU)与 iOS(CoreML)之间存在惊人的端到端差距。2026-07-22 的基准显示 iPhone 15 Pro 在 Rust 预处理上快约 12 倍、串行解码快约 4 倍,远超两颗 SoC 之间约 1.6~2 倍的真实硅片差距。本文基于仓库内的 Android ML 调度验证报告,完整复盘其四个受控实验变体、sched_getcpu()+ DVFS 频率采样等新型埋点、假设验证结论,以及按预期价值排序的六条生产落地建议。读完本文,你将掌握:如何用频率采样与线程集中来诊断"突发型负载下 CPU 提频不足"这一 Android 移动端性能顽疾,以及 Ente 计划如何通过单线程管线、CPU/GPU 流水线、ADPF 等手段回收 2.8 倍预处理性能。

一、背景:07-22 基准报告中的异常差距

验证实验的起点是 20260722_FINAL_MOBILE_ML_BENCHMARK_REPORT.md。该报告在 Pixel 8(Android 17,ONNX Runtime WebGPU)与 iPhone 15 Pro(iOS 26.5.2,ONNX Runtime CoreML)上,用同一 14 图语料测得如下稳定态数据:

设备端到端 14 图每图Rust 总耗时Rust 每图
Pixel 8 WebGPU12,994.3 ms928.2 ms7,265.3 ms518.9 ms
iPhone CoreML(warm)5,022.2 ms358.7 ms1,789.8 ms127.8 ms

其中 iPhone 端到端快 2.59 倍,Rust 管线内快约 4 倍。但分阶段看,差距分布极不均匀:

阶段Pixel 8iPhone 15 Pro差距
Decode2,771.0 ms1,169.6 ms~2.4x
Rust 预处理652.8 ms55.1 ms~11.8x
Inference(WebGPU vs CoreML)3,720.0 ms557.9 ms~6.7x
Rust 后处理12.7 ms2.3 ms~5.5x
Rust 其他117.2 ms0.5 ms

预处理 11.8 倍、后处理 5.5 倍的差距,远不能由 WebGPU/CoreML 之间的推理引擎差异(5.7~8.8x,属真实平台差距)或硅片差异解释。这构成了本次验证实验的直接动机:Pixel 的 CPU 侧慢,到底慢在硬件、并行度还是调度?

二、实验设计:四个变体与有效性控制

验证实验在ort_opt_ios分支(HEAD3c9ee2cb76追加基准埋点)上进行,设备为 Google Pixel 8(shiba),全部变体满足:AOT release(connectedIndependentReleaseAndroidTest,每轮验证dart.vm.product=true,变体 B 额外通过ML_PARITY_REQUIRE_RELEASE=true门禁)、14 图语料、每图 1 次不计时预热 + 3 次计时采样、按文件取中位数。每个变体前后设备热状态均为 1(轻度),跨变体一致,因此横向对比内部自洽。

四个变体的编译期覆盖与bench_config确认如下:

变体编译期覆盖bench_config确认
A无(基线 + 放置采样)rayon 池 9 线程,无亲和性
BENTE_ML_BENCHMARK_RAYON_THREADS=1池配置为 1 线程
CENTE_ML_BENCHMARK_CPU_AFFINITY=4-8掩码0x1f0,9/9 工作线程钉在 mid+big
D两者皆用,亲和性8(仅 Cortex-X3)池 1 线程,全部工作压到 cpu8

其中 A 为基线,B 用于检验 rayon 扇出(fan-out)是否是预处理瓶颈,C 用于检验小核放置的影响,D 用于检验"线程集中 + 单大核"能否让 DVFS 持续提频。上述ENTE_ML_BENCHMARK_*覆盖开关是基准专用、编译期可选的能力,生产构建默认不开启(07-22 报告中明确:基准日志通过ENTE_ML_BENCHMARK_LOGGING编译期 opt-in,Android release 埋点通过ENTE_ML_BENCHMARK_RELEASE_TESTS=1开启,普通构建不受影响)。

新增的埋点(编译出生产构建之外)包括:在各阶段时钟之外采样sched_getcpu()与 DVFS 频率,以及在每次管线之后运行一次空broadcast的 rayon 唤醒延迟探针。

三、结果:阶段到底跑在哪、跑在多少 MHz

Pixel 8 的集群拓扑为:cpu0-3 Cortex-A510("little",最高 1.70 GHz)、cpu4-7 Cortex-A715("mid",最高 2.37 GHz)、cpu8 Cortex-X3("big",最高 2.91 GHz)。

基线 A 下各阶段的实际放置与频率(占总阶段时间的份额):

阶段(变体 A)放置位置中位频率
decode(长突发)42% mid / 58% bigmid 1,418 MHz,big 2,687 MHz
预处理(短突发)3% little / 61% mid / 37% bigmid910 MHz,big 1,557 MHz
后处理(µs 级突发)98% mid697 MHz

这直接测量到了 07-22 分析所预测的模式:只有足够长的 decode 突发能在突发中途挣到高频率;短促的预处理/后处理突发总是"冷启动、冷结束"。ML 管线的 CPU 短突发(每次跟随约 240 ms 的 GPU 推理休眠,在约 9 个工作线程间轮转)从未在每个线程上累积出足够的利用率,让 Android 调度器提频或迁移到大核。基线预处理大部分时间跑在 mid 核上,中位仅910 MHz,只有其 2.37 GHz 上限的 38%。

变体 D(全部工作集中到一个 big 核)的效果:持续频率升至2,363 MHz,语料预处理总耗时从596.7 ms 降至 212.4 ms(2.8 倍),落入硅片应有的水平区间;尽管只用 1 个核而非 9 个核,却产生了所有变体中最快的端到端运行。

13 个共有 fixture 的语料汇总:

语料总计(ms)A:基线B:串行 rayonC:无 little 核D:串行 + 1 big 核
decode2,772.13,907.52,898.93,194.0
Rust 预处理596.7535.9472.2212.4
inference(WebGPU)3,349.53,947.73,622.83,159.8
Rust 后处理13.68.511.49.6
Rust 其他103.0119.0105.462.7
Rust 总计6,874.58,536.27,073.96,652.6

在变体 D 中,同一预处理的每次调用中位数从 15.0 ms 降到5.4 ms(p90 从 30 ms 降到 10 ms,最大值从 81 ms 降到 21 ms)。

rayon 唤醒探针(每次 resize 分发的扇出屏障开销)数据显示:变体 A 中位数 2.2 ms、p90 4.9 ms,且 46% 的池工作线程在小核上唤醒;即便在 C(全部线程钉到 mid+big)中仍是 2.4 ms 中位数——说明该开销本质是空闲线程退出延迟,而非小核放置问题;单线程池(D)下则骤降至 0.10 ms。

四、假设验证:H1 被否决,H2 被确认

H1 — rayon 扇出屏障主导预处理:被否决为主因,被确认是真实次要成本

将池串行化(B)只回收了约 597 ms 语料预处理中的约 60 ms(约 10%),且呈双峰分布:小图显著受益(1343.jpg从 39.6 ms 降至 13.0 ms——纯屏障开销),而大图或人脸密集图反而变差(pano39.7 → 59.3 ms,people.jpeg74.2 → 84.8 ms),因为丢失了真实的并行计算。结论是每次分发的 2~5 ms 屏障税真实存在但有限。

从源码可以印证该扇出的存在:ente-mlcrate 的 Cargo.toml 中fast_image_resize = { workspace = true, features = ["rayon"] }显式启用了 resize 库的 rayon 并行特性,且 crate 直接依赖rayon = "1.12.0"。实际 resize 调用链位于 preprocess.rs(YOLO 输入预处理使用fast_image_resizeResizer与双线性插值)以及 cv/resize.rs 等模块。这正是报告中"每次 resize 分发的 2~5 ms 屏障税"的代码出处。

H2 — 冷核/DVFS 放置主导:确认,且频率是决定性杠杆

排除 little 核(C)只让预处理改善 21%,因为 mid 核仍以 910 MHz 空转。把工作集中到一个核(D)后,schedutil得以维持 2,363 MHz,带来 2.8 倍改善。结论:单靠放置(affinity)不是解药,持续的利用率(sustained utilization)才是。

解码并行值得保留

串行解码(B)在语料范围内多花 +1,135 ms,几乎全部来自两个大/平铺 HEIC(pano714 → 1,426 ms,8606239 → 519 ms);普通 HEIC 本就接近串行解码。而在升频后的核(D)上,串行 JPEG/PNG/WebP 解码器反而比基线更快(astronaut.png11.6 → 5.0 ms,ui_app.webp121.5 → 79.9 ms)。

与 iPhone 的对账

在 13 个共有 fixture 上,iPhone 15 Pro 的预处理总量约 51 ms。变体 D 把 Pixel 从落后 11.7 倍拉近到约 4.2 倍;残余差距来自真实的硅片差距(单核约 2~3 倍)加上 X3 在推理休眠间隙只维持 2,363 MHz(而非 2,914 MHz)。07-22 报告中"Pixel 处处慢约 10 倍"的读法被证伪——那是在测量调度器行为,而非硬件。

五、异常与注意事项

  • CR2 平台回退失败IMG_8905.CR2在 C、D 变体中其平台 JPEG 回退失败(在 A、B 及所有 07-22 运行中成功)。两次失败都发生在测试框架开始保留已安装应用(持久化应用数据)之后,因此首要嫌疑是持久化应用数据而非亲和性覆盖本身。任何亲和性相关改动上线前需针对性重跑。共有文件分析已剔除该 fixture,头条数字不受影响。
  • WebGPU 推理波动:各变体间推理耗时 ±9% 波动(3,160~3,948 ms)且无明确排序,变体间推理差值应视为噪声。
  • 热状态差异:本次全程热状态 1(07-22 为 0),但基线 A 仍复现了 07-22 的语料总量(decode 2,772 vs 2,771 ms;预处理 597 vs 653 ms),证明埋点与热状态没有扭曲基准。
  • logcat 环形缓冲:A/B 的 logcat 各有一个 fixture 的事件在缓冲区扩容到 16 MB 前被驱逐,已由共有文件分析处理。
  • 变体 D 的诊断性质:硬钉一个核是诊断手段而非可上线配置——它独占 X3、无视热余量、与其他负载冲突。

六、生产建议:按预期价值排序

报告为生产 Android 索引给出的建议(按预期价值排序):

  1. 停止把管线工作轮转在 FRB 工作线程池上;改为在单一持久专用线程上运行 ML 管线(可选第二线程专用于解码)。这是变体 D 结论的可上线形态:线程集中才能让schedutil维持高频,第一步无需任何 pinning。
  2. CPU 与 GPU 流水线化:在图像 N 处于Session::run内时,同步解码/预处理图像 N+1。这一举两得:完全隐藏预处理延迟,同时保持工作线程高利用率以维持频率——还能同时打击解码的 2~4 倍缺口,这是单阶段修复做不到的。
  3. 采用 ADPF(PerformanceHintManager为 ML 工作线程设置每图目标时长。这是 Android 官方针对"突发型负载 + DVFS"问题的既定机制,可替代任何亲和性 hack。
  4. rust/crates/ml中移除fast_image_resizerayonfeature(保留heic_decoder自身的 rayon 并行用于解码)。resize 扇出从未回本——B 变体在无它时预处理净更快——且每次分发还要付出 2~5 ms 屏障税。小而安全、立即可做。
  5. 不要上线 CPU 亲和性 pinning,除非 CR2 异常得到解决并在争用/热负载下测试;仅当 1~3 项不达预期时才重新考虑。
  6. 修正 07-22 报告的跨平台表述:CoreML 对 WebGPU 的推理差距(5.7~8.8 倍)是真实平台差距,但预处理/后处理/解码差距约 1.6~2 倍硅片差距 + Android 调度债务,后者可由 1~4 项回收。

报告对 1+2+4 项组合(暂不含推理侧工作)的稳定态影响预估:端到端约 10~20%(本语料上预处理 597 → 约 210 ms,"其他"103 → 约 60 ms,串行解码 fixture 快 1.5~2 倍,大 HEIC 解码不变),更大的战略价值在于CPU 成本不再随调度器"心情"波动,WebGPU 推理差距成为 Android 唯一的剩余短板

七、结论:性能问题的层级与取证方法

本次验证的完整叙事是:Pixel 8 的 CPU 侧慢,根因不是硬件、也不是主要来自 rayon 扇出,而是 DVFS 与调度。短 CPU 突发跟随长 GPU 休眠、跨约 9 个线程轮转,导致每线程利用率不足、调度器不提频,基线预处理长期运行在 38% 的峰值频率上。将工作集中到单一大核后,2.8 倍性能被直接"解冻"。

这一结论对移动端 ML 工程有普遍方法学意义:

  • 跨平台基准必须先排除调度因素,才能讨论硅片差距——否则会把调度器行为误读为硬件差距;
  • 诊断突发型负载性能问题时,同时采样放置(sched_getcpu)与频率(DVFS)是不可或缺的一对观测手段;
  • 修复方向应该是线程集中 + CPU/GPU 流水线 + ADPF 提示,而不是盲目堆并行度或依赖亲和性硬钉。

相关产物与深入阅读

本次验证的机器可读产物与工具位于 infra/ml/test:

  • 各变体日志、热快照与结果载荷:infra/ml/test/out/sched_verification_2026-07-23/{A,B,C,D}/device_logcat.txt.../{A,C,D}/results.json(B 的载荷因测试框架测试后自动卸载而丢失,其基准数据完整保留在 logcat 中);
  • 分析脚本:python3 infra/ml/test/tools/analyze_ml_sched_verification.py <device_logcat.txt>(输出放置、频率、探针与语料汇总);
  • 过程文档:20260723_ANDROID_SCHED_VERIFICATION_RUNBOOK.md(与本文同目录)。

与本主题直接相关的仓库源码与配置:

  • rust/crates/ml/Cargo.toml(fast_image_resize的 rayon feature、rayon依赖、Android/iOS 的 ORT provider feature)
  • rust/crates/ml/src/preprocess.rs(YOLO 输入预处理:resize + letterbox + 归一化)
  • rust/crates/ml/src/cv/resize.rs(通用图像 resize 路径)
  • infra/ml/playground/optimizations/README.md(模型优化流水线:GELU 融合、PReLU 改写等,保证同一 ONNX 产物可被 CoreML 与 WebGPU 共用)
  • infra/ml/playground/optimizations/benchmark_reports/20260722_FINAL_MOBILE_ML_BENCHMARK_REPORT.md(本文的基线报告)

如需复现基准,可参考 infra/ml/test/run_ml_parity_tests.sh 与 infra/ml/test/README.md 了解 14 图 ML 一致性语料(含man.jpegpeople.jpegsingapore.jpg等 fixture,位于 infra/ml/playground/data)的构成与运行方式。

【免费下载链接】ente💚 End-to-end encrypted cloud for everything.项目地址: https://gitcode.com/GitHub_Trending/en/ente

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询