Optimizing Android CPU Frequency, Core Affinity, and Thread Priority
The article explains how to boost Android app performance by programmatically raising CPU frequency using Qualcomm’s BoostFramework, setting thread‑core affinity with native sched_setaffinity calls, and increasing execution priority via Process.setThreadPriority, providing Kotlin and C examples that demonstrate measurable speed gains.
Background: To further improve app performance, this article investigates how to increase CPU resource usage, raise thread execution priority, and control CPU frequency on Android devices.
CPU frequency: Modern Android phones (e.g., Mi 11 Pro) have heterogeneous cores (1 × 2.84 GHz Cortex‑X1, 3 × 2.4 GHz Cortex‑A78, 4 × 1.8 GHz Cortex‑A55). The governor (usually schedutil ) dynamically adjusts the frequency, but default limits (e.g., >10 ms step) may prevent immediate boost.
Root command to set scaling (requires root): echo [frequency] > /sys/devices/system/cpu/cpu*/cpufreq/scaling_set_speed . For non‑root apps, Qualcomm provides the BoostFramework SDK (BoostFramework.java) that can request performance hints.
Implementation – Kotlin class QcmCpuPerformance wraps the BoostFramework APIs. It defines constant configuration values (e.g., MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0 = 0x40804000 ) and provides init() , boostCpu(duration) , stopBoost() , and a private perfLockAcquire() helper. The full source is:
package com.knightboost.optimize.cpuboost
import android.content.Context
import java.lang.reflect.Method
import java.util.concurrent.CopyOnWriteArrayList
class QcmCpuPerformance : CpuPerformance {
companion object {
const val TAG = "QcmCpuPerformance"
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
const val MPCTLV3_SCHED_BOOST = 0x40C00000
}
var initSuccess = false
lateinit var acquireFunc: Method
lateinit var mPerfHintFunc: Method
lateinit var releaseFunc: Method
lateinit var frameworkInstance: Any
var boostHandlers = CopyOnWriteArrayList
()
private var CONFIGS_FREQUENCY_HIGH = intArrayOf(
MPCTLV3_SCHED_BOOST, 1,
MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 1,
MPCTLV3_MAX_FREQ_CLUSTER_BIG_CORE_0, 0xFFF,
MPCTLV3_MAX_FREQ_CLUSTER_LITTLE_CORE_0, 0xFFF,
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_PLUS_CORE_0, 0xFFF,
)
var DISABLE_POWER_COLLAPSE = intArrayOf(MPCTLV3_ALL_CPUS_PWR_CLPS_DIS, 1)
override fun init(context: Context): Boolean {
return try {
val boostFrameworkClass = Class.forName("android.util.BoostFramework")
val constructor = boostFrameworkClass.getConstructor(Context::class.java) ?: return false
frameworkInstance = constructor.newInstance(context)
acquireFunc = boostFrameworkClass.getDeclaredMethod("perfLockAcquire", Integer.TYPE, IntArray::class.java)
mPerfHintFunc = boostFrameworkClass.getMethod("perfHint", Int::class.javaPrimitiveType, String::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType)
releaseFunc = boostFrameworkClass.getDeclaredMethod("perfLockReleaseHandler", Integer.TYPE)
initSuccess = true
true
} catch (e: Exception) {
initSuccess = false
false
}
}
override fun boostCpu(duration: Int): Boolean {
if (!initSuccess) return false
return try {
perfLockAcquire(duration, DISABLE_POWER_COLLAPSE)
perfLockAcquire(duration, CONFIGS_FREQUENCY_HIGH)
true
} catch (e: Exception) {
false
}
}
override fun stopBoost() {
val handlers = boostHandlers.toTypedArray()
for (handler in handlers) {
try { releaseFunc.invoke(frameworkInstance, handler) } catch (e: Exception) { }
}
}
private fun perfLockAcquire(duration: Int, list: IntArray): Int {
val handler = acquireFunc.invoke(frameworkInstance, duration, list) as Int
if (handler > 0) boostHandlers.add(handler)
return handler
}
}Verification: reading /sys/devices/system/cpu/cpu*/cpufreq/ before and after boosting shows all cores running at maximum frequency, increasing overall CPU frequency by ~30% in idle‑to‑full‑load tests.
Linear CPU affinity: Hard affinity binds a thread to a specific set of CPUs using sched_setaffinity . Soft affinity allows migration when the target CPU is busy.
Implementation – native C function to set affinity:
#include
#include
#include
#include
JNIEXPORT jboolean JNICALL Java_com_knightboost_optimize_cpuboost_ThreadCpuAffinityManager_setCpuAffinity(JNIEnv *env, jclass clazz, jint tid, jintArray cpu_set) {
if (tid <= 0) tid = gettid();
int cpu_count = sysconf(_SC_NPROCESSORS_CONF);
jsize size = (*env)->GetArrayLength(env, cpu_set);
jint bind_cpus[size];
(*env)->GetIntArrayRegion(env, cpu_set, 0, size, bind_cpus);
cpu_set_t mask;
CPU_ZERO(&mask);
for (jint cpu : bind_cpus) {
if (cpu > 0 && cpu < cpu_count) {
CPU_SET(cpu, &mask);
} else {
__android_log_print(ANDROID_LOG_ERROR, "TCpuAffinity", "illegal cpu index %d", cpu);
}
}
int code = sched_setaffinity(tid, sizeof(mask), &mask);
return code == 0 ? JNI_TRUE : JNI_FALSE;
}Verification of affinity uses the 39th field of /proc/ /task/ /stat to read the last CPU on which the thread ran:
fun getLastRunOnCpu(tid: Int): Int {
val path = "/proc/${android.os.Process.myPid()}/task/${tid}/stat"
return try {
val content = File(path).readText()
val fields = content.split(' ')
fields[38].toInt()
} catch (e: Exception) { -1 }
}Thread priority: Android provides Process.setThreadPriority(tid, priority) (Linux nice range –20 ~ 19) and Thread.setPriority() (Java range 1 ~ 10). Experiments show that setting the Linux priority to –20 gives the thread ~98% CPU time, while default priority yields a fair share.
Verification includes logs and screenshots demonstrating the impact of priority on CPU time slices.
Summary: The article presents practical techniques for controlling CPU frequency via Qualcomm BoostFramework, binding threads to specific cores with sched_setaffinity , and adjusting thread priority on Android. These methods can be applied to improve cold‑start, UI rendering, and other performance‑critical scenarios.
DeWu Technology
A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.