容量是指设备在一段时间内拥有的某种资源(CPU、GPU 等)的总量。本页介绍如何识别和解决与容量相关的卡顿问题。
Governor 反应迟缓
为了避免卡顿,CPU 频率调节器需要能够快速响应突发工作负载。大多数 UI 应用都遵循相同的基本模式
- 用户正在阅读屏幕。
- 用户触摸屏幕:点击按钮、滚动等。
- 屏幕滚动、更改 Activity 或以某种方式动画响应输入。
- 当显示新内容时,系统进入静止状态。
- 用户返回阅读屏幕。
Pixel 和 Nexus 设备实现了触摸加速功能,以在触摸时修改 CPU 频率调节器(和调度器)的行为。为了避免缓慢提升到高时钟频率(这可能会导致设备在触摸时丢帧),触摸加速通常会在 CPU 上设置一个频率下限,以确保在触摸时有足够的 CPU 容量可用。下限会在触摸后持续一段时间(通常约为两秒)。
Pixel 还使用能源感知调度 (EAS) 提供的 schedtune cgroup 作为额外的触摸加速信号:顶级应用通过 schedtune 获得额外的权重,以确保它们获得足够的 CPU 容量来快速运行。与使用 Kryo CPU 的 Pixel 相比,Nexus 5X 和 6P 的小 CPU 集群(A53)和大 CPU 集群(A57)之间存在更大的性能差距。我们发现,小 CPU 集群并不总是足以实现流畅的 UI 渲染,尤其是在设备上存在其他抖动源的情况下。
因此,在 Nexus 5X 和 6P 上,触摸加速会修改调度器行为,使其更有可能将前台应用移动到大核(这在概念上类似于 CPU 频率下限)。如果没有调度器更改来使前台应用更有可能移动到大 CPU 集群,则前台应用可能没有足够的 CPU 容量来进行渲染,直到调度器决定将线程负载均衡到大 CPU 核。通过在触摸加速期间更改调度器行为,UI 线程更有可能立即在大核上运行并避免卡顿,同时又不会强制其始终在大核上运行,否则可能会对功耗产生严重影响。
热节流
当设备必须降低其整体热输出时,就会发生热节流,通常通过降低 CPU、GPU 和 DRAM 时钟来执行。不出所料,这通常会导致卡顿,因为系统可能不再能够提供足够的容量在给定的时间片内进行渲染。避免热节流的唯一方法是降低功耗。有很多方法可以做到这一点,但根据我们过去使用 SOC 的经验,我们对系统供应商有一些建议。
首先,在构建具有异构 CPU 架构的新 SOC 时,请确保 CPU 集群的性能/W 曲线重叠。整个处理器的总体性能/W 曲线应为一条连续线。perf/W 曲线中的不连续性迫使调度器和频率调节器猜测工作负载的需求;为了防止卡顿,调度器和频率调节器会倾向于为工作负载提供比其需要的更多的容量。这会导致功耗过高,从而导致热节流。
假设一个具有两个 CPU 集群的虚拟 SOC
- 集群 1,即小集群,可以消耗 100-300mW 的功率,并在吞吐量基准测试中获得 100-300 分,具体取决于时钟。
- 集群 2,即大集群,可以消耗 1000 到 1600mW 的功率,并在相同的吞吐量基准测试中获得 800 到 1200 分,具体取决于时钟。
在此基准测试中,分数越高速度越快。虽然速度更快并非更理想,但速度更快 == 功耗更高。
如果调度器认为 UI 工作负载需要在该吞吐量基准测试中获得相当于 310 分的分数,那么避免卡顿的最佳选择是以最低频率运行大集群,从而浪费大量功率。(这取决于 cpuidle 行为和竞争进入空闲状态;具有连续 perf/W 曲线的 SOC 更容易优化。)
其次,使用 cpusets。确保在您的内核和 BoardConfig.mk
中启用了 cpusets。您还必须在特定于设备的 init.rc
中设置实际的 cpuset 分配。一些供应商在其 BSP 中禁用此功能,希望他们可以使用其他提示来影响调度器行为;我们认为这没有意义。cpusets 有助于确保 CPU 之间的负载均衡以反映用户在设备上实际执行的操作的方式完成。
ActivityManager 根据应用的相关重要性(顶级、前台、后台)将应用分配到不同的 cpusets,更重要的应用获得更多对 CPU 核心的访问权限。这有助于确保前台和顶级应用的服务质量。
cpusets 在同构 CPU 配置上很有用,但是您不应在未启用 cpusets 的情况下发布具有异构 CPU 配置的设备。Nexus 6P 是如何在异构 CPU 配置上使用 cpusets 的一个很好的模型;将其用作您自己设备配置的基础。
cpusets 还提供功耗优势,通过确保非性能关键的后台线程永远不会负载均衡到大 CPU 核心,否则它们可能会消耗明显更多的功率,而没有任何用户可感知的益处。这也有助于避免热节流。虽然热节流是一个容量问题,但抖动改进对热节流时的 UI 性能具有格外大的影响。因为系统将更接近其渲染 60FPS 的能力运行,所以需要更少的抖动来导致丢帧。