-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
摘要
-
说明:通过
JNI在应用层读取/sys/devices/system/cpu下各核的cpuinfo_max_freq,选出频率最高的核心集合,随机挑选一个并尝试把主线程绑定到该核,以期望获得更稳定或更高的主线程性能。 -
目的:在需要主线程更稳定的短时间高负载场景(如关键 UI 动画或延迟敏感计算)尝试降低抖动。
实现要点
-
native 侧实现三个 JNI 方法:
getMaxFreqCores、bindThreadToCore、getCurrentCpu;应用层调用这些方法决定是否绑定主线程。 -
getMaxFreqCores 通过读取每个
cpuN/cpufreq/cpuinfo_max_freq找出最大频率并返回所有匹配核心索引。 -
bindThreadToCore 用
sched_setaffinity将当前线程绑定到指定 CPU。 -
getCurrentCpu 用
sched_getcpu返回当前线程运行的 CPU 编号,用于验证绑定是否生效。
示例代码
JNI:
#include <jni.h>
#include <string>
#include <unistd.h>
extern "C"
JNIEXPORT jintArray JNICALL
Java_XXX_getMaxFreqCores(JNIEnv *env, jobject /* this */) {
char path[128];
FILE *fp;
int maxFreq = -1;
// 获取CPU核心数
int cpuCount = sysconf(_SC_NPROCESSORS_ONLN);
int cores[cpuCount];
int coreCount = 0;
// 第一次遍历,找最大频率
for (int i = 0; i < cpuCount; i++) {
snprintf(path, sizeof(path),
"/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
fp = fopen(path, "r");
if (fp) {
int freq = 0;
if (fscanf(fp, "%d", &freq) == 1) {
if (freq > maxFreq) {
maxFreq = freq;
}
}
fclose(fp);
} else {
break; // 核心不存在
}
}
// 第二次遍历,把所有等于 maxFreq 的核心加入数组
for (int i = 0; i < cpuCount; i++) {
snprintf(path, sizeof(path),
"/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
fp = fopen(path, "r");
if (fp) {
int freq = 0;
if (fscanf(fp, "%d", &freq) == 1) {
if (freq == maxFreq) {
cores[coreCount++] = i;
}
}
fclose(fp);
} else {
break;
}
}
// 返回期望的结果
jintArray result = env->NewIntArray(coreCount);
if (result == nullptr) return nullptr;
env->SetIntArrayRegion(result, 0, coreCount, cores);
return result;
}
extern "C"
JNIEXPORT jint JNICALL
Java_XXX_bindThreadToCore(JNIEnv *env, jobject /* this */, jint core) {
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(core, &set);
pid_t tid = gettid();
int result = sched_setaffinity(tid, sizeof(set), &set);
return result; // 0 = 成功, -1 = 失败
}
extern "C"
JNIEXPORT jint JNICALL
Java_XXX_getCurrentCpu(JNIEnv *env, jobject /* this */) {
return sched_getcpu();
}应用层调用:
class MainActivity : AppCompatActivity() {
companion object {
init {
System.loadLibrary("jni")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val maxFreqCores = getMaxFreqCores()
maxFreqCores.forEach { core ->
Log.d("Tyhoo", "最高频率核心: cpu$core")
}
val result = isCurrentInMaxFreqCore(maxFreqCores)
if (!result) {
// 随机选择一个最高频率核心
val randomMaxFreqCore = maxFreqCores.random()
Log.d("Tyhoo", "将主线程绑定到最高频率核心 cpu$randomMaxFreqCore")
val ret = bindThreadToCore(randomMaxFreqCore)
if (ret == 0) {
Log.d("Tyhoo", "主线程已绑定到 cpu$randomMaxFreqCore")
isCurrentInMaxFreqCore(maxFreqCores)
} else {
Log.d("Tyhoo", "绑定失败,错误码: $ret")
}
}
}
private fun isCurrentInMaxFreqCore(cores: IntArray): Boolean {
val currentCpu = getCurrentCpu()
if (cores.contains(currentCpu)) {
Log.d("Tyhoo", "主线程正在运行在最高频率核心 cpu$currentCpu")
return true
} else {
Log.d("Tyhoo", "主线程在 cpu$currentCpu, 不是最高频率核心 ${cores.joinToString(", ") { "cpu$it" }}")
return false
}
}
external fun getMaxFreqCores(): IntArray
external fun bindThreadToCore(core: Int): Int
external fun getCurrentCpu(): Int
}打印日志:
com.tyhoo.example.jni D 最高频率核心: cpu0
com.tyhoo.example.jni D 最高频率核心: cpu1
com.tyhoo.example.jni D 最高频率核心: cpu2
com.tyhoo.example.jni D 最高频率核心: cpu3
com.tyhoo.example.jni D 主线程在 cpu5, 不是最高频率核心 cpu0, cpu1, cpu2, cpu3
com.tyhoo.example.jni D 将主线程绑定到最高频率核心 cpu1
com.tyhoo.example.jni D 主线程已绑定到 cpu1
com.tyhoo.example.jni D 主线程正在运行在最高频率核心 cpu1结论
该方案实现简单、不改动架构,适合做短期实验和定位性能抖动。但生产环境使用前必须做好兼容性、稳健性与性能回归测试,避免因绑定主线程带来意外副作用。