讲在前面的话
根据数据统计,目前市面搭载高通芯片的手机品牌占着绝对大的份额,截止发稿前,在手机端的高通芯片最能打的应该为骁龙8Gen3处理器了吧,当然手机性能是越来越好,对用户使用体验也越来越友好。
作为开发者大家都知道,CPU的执行频率越高,可执行的代码量也就越多。不知道各位是否遇到过这样的情况,可能在某个需求当中,系统侧会判定你并不需要更高的执行频率,而恰恰相反,你却期望主动的提升CPU的执行频率,加速执行的过程:比如加速打开某个页面、加速起播、减少卡顿等等。
一、了解 "BoostFramework"
为了保证Android系统的顺滑体验,各个厂家都有针对性的对Android系统做了性能优化的方案。高通也基于AOSP开发了一套性能优化框架。
BoostFramework 可以理解为高通开发的一个性能SDK,主要作用是给应用提供性能提升的相关能力。以应用启动场景为例。在应用启动时,系统识别到这个场景,会使用BoostFramework SDK提升CPU的频率,以此来达到提升应用启动性能的目的。 先看一张结构图:
通过阅读BoostFramework的源码,可以发现其实现主要是对 QPerformance.jar 和UxPerformance.jar中的 API 进行了反射调用包装。那么一样的,我们也可以通过封装对BoostFrameWork类的调用提供提频能力。
另外,如何确定我们的设备包含高通的这套性能调控SDK呢?可以通过查看你的Android设备存储路径/system/framework/路径,如果包含了 QPerformance.jar 及 QXPerformance.jar 就表示接入了SDK。
不过这些函数似乎并不是默认公开的内容,直接通过google搜索 并没有找到关于BoostFramwork或者高通Performance API的相关信息。最后还是通过其他各种关键字检索,终于找到了部分有效信息。
二、如何控制操作提频
来到这里,我就需要先介绍一下 PerfLock API 了,其实 PerfLock API 就是高通骁龙芯片厂商对外提供的操作芯片封装的一套SDK架构,可以充分发挥CPU的性能及调度。
下面就是核心的操作的API内容:
=========================================================================================
DescriptionMPCTLV3_ALL_CPUS_PWR_CLPS_DIS
=========================================================================================
The PerfLock APIs can be used in either the framework or in packaged applications.
The APIs toggle system performance optimizations based upon level requested.
PerfLock will always run the highest level of optimization requested.
NOTE: Each instance of the Performance class object will serve one unique PerfLock request.
Therefore, a new Performance class object will need to be created for every
unique request for PerfLock.
Please read through the following carefully to understand the proper usage of this API.
=========================================================================================
PerfLock APIs
=========================================================================================
The following two methods are the PerfLock APIs
1. perfLockAcquire(int duration, int... args)
Description:
Toggle on all optimizations requested.
Arguments:
duration: The maximum amount of time required to hold the lock.
Only a positive integer value in milliseconds will be accepted.
You may explicitly call perfLockRelease before the timer expires.
args: Enter all optimizations required. Only the optimizations in the
table below are supported. You can only choose one optimization
from each of the numbered sections in the table. Incorrect or
unsupported optimizations will be ignored.
NOTE: Enter the optimizations required in the order they appear in the table.
Returns: REQUEST_SUCCEEDED or REQUEST_FAILED.
2. perfLockRelease()
Description:
Toggle off all optimizations requested.
Use this function if you want to release before the time duration ends.
Arguments: None.
Returns: REQUEST_SUCCEEDED or REQUEST_FAILED.
=========================================================================================
Optimizations Supported
=========================================================================================
The following resource optimizations are supported:
===============================================================================================
| | | |
| Section | Optimization | Description |
| | | |
===============================================================================================
| 1 | ALL_CPUS_PWR_CLPS_DIS | Disables power collapse on all CPUs |
| | | |
===============================================================================================
| 2 | CPUS_ON_MAX | Minimum of all cores on |
| |________________________________________|____________________________________________|
| | CPUS_ON_3 | Minimum of three cores on |
| |________________________________________|____________________________________________|
| | CPUS_ON_2 | Minimum of two cores on |
| |________________________________________|____________________________________________|
| | CPUS_ON_LIMIT_1 | Maximum of one core on |
| |________________________________________|____________________________________________|
| | CPUS_ON_LIMIT_2 | Maximum of two cores on |
| |________________________________________|____________________________________________|
| | CPUS_ON_LIMIT_3 | Maximum of three cores on |
| | | |
===============================================================================================
| For the following CPU FREQ resources, please read carefully on the usage. |
| All frequencies available on the device are supported. In order to use an intermediate |
| frequency not specified with an enum, you will need to pass in a valid hex value. |
| The leftmost byte represents the CPU and the rightmost byte represents the frequency. |
| The hex value used will be multiplied by 10^5 to calculate the minimum frequency requested. |
| This calculated frequency or the next highest frequency available will be set. |
| |
| Example: Set CPU0 frequency to a minimum of 700 Mhz |
| Use 0x207. |
| |
| Example: Set CPU1 frequency to a maximum of 2.0 Ghz |
| Use 0x1614. |
| |
===============================================================================================
| 3 | CPU0_FREQ_LVL_TURBO_MAX = 0x2FE | Set CPU0 minimum frequency to device max |
| |________________________________________|____________________________________________|
| | CPU0_FREQ_LVL_NONTURBO_MAX = 0x20A | Set CPU0 minimum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 4 | CPU1_FREQ_LVL_TURBO_MAX = 0x3FE | Set CPU1 minimum frequency to device max |
| |________________________________________|____________________________________________|
| | CPU1_FREQ_LVL_NONTURBO_MAX = 0x30A | Set CPU1 minimum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 5 | CPU2_FREQ_LVL_TURBO_MAX = 0x4FE | Set CPU2 minimum frequency to device max |
| |________________________________________|____________________________________________|
| | CPU2_FREQ_LVL_NONTURBO_MAX = 0x40A | Set CPU2 minimum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 6 | CPU3_FREQ_LVL_TURBO_MAX = 0x5FE | Set CPU3 minimum frequency to device max |
| |________________________________________|____________________________________________|
| | CPU3_FREQ_LVL_NONTURBO_MAX = 0x50A | Set CPU3 minimum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 7 | CPU0_MAX_FREQ_LVL_NONTURBO_MAX = 0x150A| Set CPU0 maximum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 8 | CPU1_MAX_FREQ_LVL_NONTURBO_MAX = 0x160A| Set CPU1 maximum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 9 | CPU2_MAX_FREQ_LVL_NONTURBO_MAX = 0x170A| Set CPU2 maximum frequency to 1026 Mhz |
| | | |
===============================================================================================
| 10 | CPU3_MAX_FREQ_LVL_NONTURBO_MAX = 0x180A| Set CPU3 maximum frequency to 1026 Mhz |
| | | |
===============================================================================================
通过对应API文档及使用示例得知perfLocakAcquire 该函数接受 2个参数,第一个参数为持续时间、第二个参数为一个int数组,表示具体的操作,数组中的内容为 k-v 结构形式,比如 [config1,value,config2,value] . 该函数执行时会返回一个 PerfLock句柄,后续通过调用 perfLockReleaseHandler 可以提前取消之前的操作。
这里简单列举一下配置项的对应值:
/**
* 是否允许CPU进入深度低功耗模式
*/
const val MPCTLV3_TOGGLE_POWER_COLLAPSE = 0x40400000
/**
* 是否允许CPU进入深度低功耗模式, 对应 /dev/cpu_dma_latency, 默认空,不允许则设置为1
*/
const val MPCTLV3_ALL_CPUS_PWR_CLPS_DIS = 0x40400000
/**
* 设置小核最小频率,十六进制
*/
const val MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0 = 0x40800100
/**
* 设置小核最大频率,十六进制
*/
const val MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0 = 0x40804100
/**
* 设置大核最小频率,十六进制
*/
const val MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0 = 0x40800000
/**
* 设置大核最大频率,十六进制
*/
const val MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0 = 0x40804000
/**
* 对应控制超大核最小频率
*/
const val MPCTLV3_MIN_FREQ_CLUSTER_PLUS_CORE_0 = 0x40800200;
/**
* 对应控制超大核最小频率
*/
const val MPCTLV3_MAX_FREQ_CLUSTER_PLUS_CORE_0 = 0x40804200
/**
* SCHED 加速类型
* 1 (Fullthrottle), 2(Conservative),3(Restrained)
*/
const val MPCTLV3_SCHED_BOOST = 0x40C00000
/**
* 设置GPU最小PowerLevel,十六进制
*/
const val MPCTLV3_GPU_MIN_POWER_LEVEL = 0X42804000
/**
* 设置GPU最大PowerLevel,十六进制
*/
const val MPCTLV3_GPU_MAX_POWER_LEVEL = 0X42808000
/**
* 最小几个大核Online
*/
const val MPCTLV3_MIN_ONLINE_CPU_CLUSTER_BIG = 0x41000000
/**
* 最多几个大核Online
*/
const val MPCTLV3_MAX_ONLINE_CPU_CLUSTER_BIG = 0x41004000
/**
* 最小几个小核Online
*/
const val MPCTLV3_MIN_ONLINE_CPU_CLUSTER_LITTLE = 0x41000100
/**
* 最多几个小核Online
*/
const val MPCTLV3_MAX_ONLINE_CPU_CLUSTER_LITTLE = 0x41004100
/**
* 最小几个超大核Online
*/
const val MPCTLV3_MIN_ONLINE_CPU_CLUSTER_PRIME = 0x41000200
/**
* CPU请求的最小DDR频率
*/
const val MPCTLV3_CPUBW_HWMON_MIN_FREQ = 0x41800000
/**
* CPU请求的最大DDR频率
*/
const val MPCTLV3_CPUBW_HWMON_MAX_FREQ = 0x41818000
1. 反射 BoostFramework 操作实例
通过下方的操作方式先创建操作对象及实例:
try {
val boostFrameworkClass = Class.forName("android.util.BoostFramework")
} catch (e: Throwable) {
Log.e("soc", "load class error!", e)
}
try {
var constructor = boostFrameworkClass?.getConstructor(Context::class.java)
} catch (e: Throwable) {
Log.e("soc", "getConstructor for context error!", e)
}
if (constructor == null) {
try {
constructor = boostFrameworkClass?.getConstructor()
} catch (e: Throwable) {
Log.e("soc", "getConstructor error!", e)
}
}
try {
var frameworkInstance = constructor?.newInstance(context)
} catch (e: Throwable) {
Log.e("soc", "newInstance for context error!", e)
}
if (frameworkInstance == null) {
try {
frameworkInstance = constructor?.newInstance()
} catch (e: Throwable) {
Log.e("soc", "newInstance error!", e)
}
}
try {
val acquireFunc = boostFrameworkClass?.getDeclaredMethod(
"perfLockAcquire", Integer.TYPE, IntArray::class.java
)
} catch (e: Throwable) {
Log.e("soc", "perfLockAcquire not exit!", e)
}
try {
var releaseFunc = boostFrameworkClass?.getDeclaredMethod(
"perfLockReleaseHandler", Integer.TYPE
)
} catch (e: Throwable) {
Log.e("soc", "perfLockReleaseHandler not exit!", e)
}
if (releaseFunc == null) {
try {
releaseFunc = boostFrameworkClass?.getDeclaredMethod("perfLockRelease")
} catch (e: Throwable) {
Log.e("soc", "perfLockRelease not exit!", e)
}
}
2. 提频动作的关键API
可以看到,这里接收两个参数,第一参数是代表了执行的时长,第二个参考代表操作操作的指令。
/**
* Toggle on all optimizations requested.
* @param duration: The maximum amount of time required to hold the lock.
* Only a positive integer value in milliseconds will be accepted.
* You may explicitly call perfLockRelease before the timer expires.
* @param list Enter all optimizations required. Only the optimizations in the
* table below are supported. You can only choose one optimization
* from each of the numbered sections in the table. Incorrect or
* unsupported optimizations will be ignored.
*
* NOTE: Enter the optimizations required in the order they appear in the table.
*/
private fun perfLockAcquire(duration: Int, list: IntArray): Int {
var ret = -1
try {
ret = acquireFunc?.invoke(frameworkInstance, duration, list) as? Int ?: -1
} catch (e: Throwable) {
Log.e("soc", "perfLockAcquire: ", e)
}
return ret
}
private fun perfLockReleaseHandler(handle: Int): Int {
var ret = -1
try {
ret = releaseFunc?.invoke(frameworkInstance, handle) as? Int ?: -1
} catch (e: Throwable) {
Log.e("soc", "perfLockReleaseHandler: ", e)
try {
ret = releaseFunc?.invoke(frameworkInstance) as? Int ?: -1
} catch (e1: Throwable) {
Log.e("soc", "perfLockReleaseHandler for perfLockRelease: ", e1)
}
}
return ret
}
这里给出一个操作的快捷指令仅供参考:
// 1. 请求将所有CPU核心频率拉满,并禁止进入深入低功耗模式
// 2. 大核、小核、超大核都切成turbo模式
// 3. 关闭power collapse
// 4. 使能SCHED_BOOST
private val CONFIGS_FREQUENCY_HIGH = intArrayOf(
// Disable power collapse and set CPU clocks to turbo
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 0x1,
MPCTLV3_SCHED_BOOST, 0x1,
MPCTLV3_MIN_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_MIN_FREQ_CLUSTER_PLUS_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_PLUS_CORE_0, 0xFFF,
)
三、实操起来
通过读取/sys/devices/system/cpu/cpu[0-7]/cpufreq/下的文件可以读取最大、最小、以及当前运行的CPU频率。
1. 查询cpu支持的频率
/sys/devices/system/cpu/cpu[0-7]/cpufreq/scaling_available_frequencies
2. 查询cpu当前频率
/sys/devices/system/cpu/cpu[0-9]/cpufreq/scaling_cur_freq
3. 查询cpu最大频率
/sys/devices/system/cpu/cpu[0-9]/cpufreq/scaling_max_freq
4. 查询cpu最小频率
/sys/devices/system/cpu/cpu[0-9]/cpufreq/scaling_min_freq
在提频前,当前设备的CPU频率信息如下:
可以发现提频前,cpu[0-3] 这些小核中,都运行在中间的一些支持的频率当中,cpu[4-5]中核都运行在最小频率,7号大核直接摸鱼运行在最小频率。
在提频后,运行数据如下:
可以看出,进行提频后,所有核心都运行在最大频率上,整机频率相比之前提升50%, 当然在实际运行过程中,提频前的工作频率并不会这么低,这里的数据是从CPU几乎空闲状态到直接满频的情况。