google官方性能文档:Android 动态性能框架优化散热和 CPU 性能-Thermal API部分
利用 Android 动态性能框架优化散热和 CPU 性能
本指南介绍了如何使用 Android 动态性能框架 (ADPF) 根据 Android 上的动态散热和 CPU 管理功能优化游戏。这些功能侧重于游戏,但也可以用于其他性能密集型应用。
ADPF 是一组 API,可让游戏和性能密集型应用更为直接地与 Android 设备的电源和散热系统进行互动。借助这些 API,您可以监控 Android 系统上的动态行为,在不造成设备过热问题的可持续界限内优化游戏性能。
与桌面设备和游戏机相比,移动 SoC 和 Android 具有更多的动态性能行为。这些行为包括热状态管理、不同的 CPU 时钟和不同的 CPU 核心类型。再加上 SoC 核心拓扑日益多样化,这给尝试确保您的游戏能够利用这种行为而不对设备性能产生负面影响时带来了挑战。ADPF 提供其中一些信息是为了提高性能的可预测性。
以下是主要的 ADPF 功能:
Thermal API:
监控设备的热状态,以便应用在工作负载变得不可持续之前主动调整工作负载。
CPU Performance Hint API:
提供性能提示,让 Android 能够为工作负载选择合适的性能设置(例如 CPU 操作点或核心)。
Game Mode API 和 Game State API:
根据用户的设置和游戏专用配置,通过确定性能或电池续航时间特征的优先级来启用游戏优化功能。
固定性能模式:
在进行基准测试期间在设备上启用固定性能模式,以获取不会因动态 CPU 时钟设置而更改的测量结果。
节能模式:
告知会话可以安全地安排性能提示会话中的线程,使其优先考虑节能而非性能。(适用于 Android 15)
下面来重点介绍一下 Thermal API 。
Thermal API
已发布:
Android 11(API 级别 30)- 热 API
Android 12(API 级别 31)- NDK API
(预览版)Android 15 (DP1) - getThermalHeadroomThresholds()
应用的潜在性能受设备热状态的限制,热状态可能会因天气、近期使用情况以及设备热设计等特性而异。设备只能在限定的时间内保持高水平的性能,然后便会受到热限制。实现的关键目标是在不超出热限制的情况下实现性能目标。借助 Thermal API,您无需进行特定于设备的优化即可实现此目的。此外,在调试性能问题时,了解设备热状态是否会限制性能非常重要。
游戏引擎通常具有运行时性能参数,可以调整引擎对设备施加的工作负载。例如,这些参数可以设置工作器线程数量、大核心和小核心的工作器线程亲和性、GPU 保真度选项以及帧缓冲区分辨率。在 Unity Engine 中,游戏开发者可以使用自适应性能插件更改质量设置,从而调整工作负载。对于 Unreal Engine,请使用可伸缩性设置动态调整画质级别。
当设备接近不安全的热状态时,您的游戏可以通过借助这些参数降低工作负载来避免受到限制。为避免受到限制,您应监控设备的热状态并主动调整游戏引擎工作负载。设备过热后,工作负载必须降至可持续的性能水平以下,以便进行散热。当热余量降至更安全的水平后,游戏可以再次提高画质设置,但请务必找到可持续的画质级别,以获得最佳游戏时间。
您可以通过轮询 getThermalHeadroom 方法来监控设备的热状态。此方法用于预测设备可以在不过热的情况下保持当前性能水平多长时间。如果时间低于运行工作负载所需的时间量,您的游戏应将工作负载降低到可持续水平。例如,游戏可以切换到较小的核心、降低帧速率或降低保真度。
注意:如果您的游戏从玩家那里收集性能遥测数据,那么设备热状态就是一项值得关注的指标,因为它可以为所有相关问题提供更多上下文信息。
ADPF Thermal API 集成前准备
图 1. 不主动监控 getThermalHeadroom 的热余量
ADPF Thermal API 集成后
图 2. 热余量,以及对 getThermalHeadroom
的积极监控
获取热管理器
如需使用 Thermal API,您首先需要获取 Thermal Manager
PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);
提前 x 秒预测热余量,以便更好地进行控制
您可以让系统根据当前工作负载预测 x 秒后的温度。这样,您可以通过减少工作负载来防止热节流功能启用,从而实现更精细的控制,并有更多时间做出响应。
结果范围为 0.0f(无节流,THERMAL_STATUS_NONE)到 1.0f(重度节流,THERMAL_STATUS_SEVERE)。如果您的游戏具有不同的图形质量级别,您可以遵循我们的热余量准则。
float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + thermalHeadroom);
注意 :如果 getThermalHeadroom 返回 NaN,请确保每 10 秒调用该函数的次数不超过 1 次。如果它仍然返回 NaN,则表示设备型号可能没有热管理硬件,并且不支持 Thermal API。
或者,依靠热状态进行说明
每种设备型号的设计可能有所不同。某些设备或许能够更好地分配热量,因此在受到节流限制之前能够承受更高的热余量。如果您想读取热余量范围的简化分组,可以查看热状态,以了解当前设备上的热余量值。
int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);
注意: 在一个设备型号上,相同的 thermalHeadroom 值可能会映射到某个 thermalStatus,但在另一个设备上,它可能会映射到其他 thermalStatus。这是由于设备设计、热特性和性能配置的差异所致,属于正常现象。
注意: 部分设备可能尚不完全支持此技术,无论热余量和节流状态的实际值如何,都会返回 THERMAL_STATUS_NONE。因此,我们建议改用 getThermalHeadroom。如需了解此情况的解决方案,请参阅 Thermal API 的设备限制。
在热状态发生变化时接收通知
您还可以避免轮询 thermalHeadroom,直到 thermalStatus 达到特定级别(例如:THERMAL_STATUS_LIGHT)。为此,您可以注册回调,以便系统在状态发生变化时通知您。
注意: 请参阅 Thermal API 的设备限制,并不要仅依赖 GetCurrentThermalStatus(),而应通过 GetThermalHeadroom() 进行验证
// PowerManager.OnThermalStatusChangedListener is an interface, thus you can
// also define a class that implements the methods
PowerManager.OnThermalStatusChangedListener listener = newPowerManager.OnThermalStatusChangedListener() {@Overridepublic void onThermalStatusChanged(int status) {Log.d("ADPF", "ThermalStatus changed: " + status);// check the status and flip the flag to start/stop pooling when// applicable}
};
powerManager.addThermalStatusListener(listener);
完成后,请记得移除监听器
powerManager.removeThermalStatusListener(listener);
清理
完成后,您需要清理所获取的 thermal_manager。如果您使用的是 Java,系统可以自动为您回收 PowerManager 引用。但是,如果您通过 JNI 使用 Java API 并保留了引用,请务必清理引用!
AThermal_releaseManager(thermal_manager);
如需有关如何同时使用 C++ API (NDK API) 和 Java API(通过 JNI)在原生 C++ 游戏中实现 Thermal API 的完整指南,请参阅自适应性 Codelab 中的集成 Thermal API 部分。
热余量指南
您可以通过轮询 getThermalHeadroom 方法来监控设备的热状态。此方法可预测设备在达到 THERMAL_STATUS_SEVERE 之前可以保持当前性能水平多长时间。例如,如果 getThermalHeadroom(30) 返回 0.8,则表示在 30 秒内,余量预计将达到 0.8,距离严重节流(即 1.0)还有 0.2 的距离。如果时间低于运行工作负载所需的时间量,您的游戏应将工作负载降低到可持续水平。例如,游戏可以降低帧速率、降低保真度或减少网络连接工作。
热状态和含义
如果设备未受到热限制:
THERMAL_STATUS_NONE
受到一些限制,但对性能没有显著影响:
THERMAL_STATUS_LIGHT
THERMAL_STATUS_MODERATE
受到重大限制,性能受到影响:
THERMAL_STATUS_SEVERE
THERMAL_STATUS_CRITICAL
THERMAL_STATUS_EMERGENCY
THERMAL_STATUS_SHUTDOWN
Thermal API 的设备限制
由于旧款设备上热管理 API 的实现方式,热管理 API 存在一些已知限制或额外要求。限制和解决方法如下:
请勿过于频繁地调用 GetThermalHeadroom() API。如果您这样做,API 会返回 NaN。每 10 秒调用该方法的次数不应超过 1 次。
避免从多个线程调用,因为这样更难确保调用频率,并且可能会导致 API 返回 NaN。
如果 GetThermalHeadroom() 的初始值为 NaN,则表示设备上不支持该 API
如果 GetThermalHeadroom() 返回较高的值(例如 0.85 或更高),而 GetCurrentThermalStatus() 仍返回 THERMAL_STATUS_NONE,则状态可能不会更新。使用启发词语来估算正确的热节流状态,或者只使用 getThermalHeadroom() 而不使用 getCurrentThermalStatus()。
启发法示例:
检查 Thermal API 是否受支持。isAPISupported() 会检查对 getThermalHeadroom 的第一次调用的值,以确保其不为 0 或 NaN,如果第一个值为 0 或 NaN,则会跳过使用该 API。
如果 getCurrentThermalStatus() 返回的值不是 THERMAL_STATUS_NONE,则表示设备正在受热限制。
如果 getCurrentThermalStatus() 一直返回 THERMAL_STATUS_NONE,并不一定表示设备未受到热限制。这可能表示设备不支持 getCurrentThermalStatus()。检查 getThermalHeadroom() 的返回值,确保设备处于良好状态。
如果 getThermalHeadroom() 返回的值大于 1.0,则实际状态可能是 THERMAL_STATUS_SEVERE 或更高,请立即减少工作负载并保持较低的工作负载,直到 getThermalHeadroom() 返回较低的值
如果 getThermalHeadroom() 返回值为 0.95,实际状态可能为 THERMAL_STATUS_MODERATE 或更高,请立即减少工作负载并保持警惕,以防止读数更高
如果 getThermalHeadroom() 返回值为 0.85,则实际状态可能是 THERMAL_STATUS_LIGHT,请保持警惕并尽可能减少工作负载
伪代码:
bool isAPISupported() {float first_value_of_thermal_headroom = getThermalHeadroom();if ( first_value_of_thermal_headroom == 0 ||first_value_of_thermal_headroom == NaN ) {// Checked the thermal Headroom API's initial return value// it is NaN or 0,so, return false (not supported)return false;}return true;}if (!isAPISupported()) {// Checked the thermal Headroom API's initial return value, it is NaN or 0// Don’t use the API} else {// Use thermalStatus API to check if it returns valid values.if (getCurrentThermalStatus() > THERMAL_STATUS_NONE) {// The device IS being thermally throttled} else {// The device is not being thermally throttled currently. However, it// could also be an indicator that the ThermalStatus API may not be// supported in the device.// Currently this API uses predefined threshold values for thermal status// mapping. In the future you may be able to query this directly.float thermal_headroom = getThermalHeadroom();if ( thermal_headroom > 1.0) {// The device COULD be severely throttled.} else if ( thermal_headroom > 0.95) {// The device COULD be moderately throttled.} else if ( thermal_headroom > 0.85) {// The device COULD be experiencing light throttling.}}}
示意图:
图 3:用于确定旧款设备上是否支持 Thermal API 的启发词语示例
原文链接参考:
https://developer.android.google.cn/games/optimize/adpf?hl=zh-cn
更多framework实战干货,请关注下面“千里马学框架”