1、先用下面的命令查看CPU核心数和大小核分布
adb shell
cat /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq
cat /proc/cpuinfo
例如下面是车机端高通6125芯片(8核)的CPU核心分布情况
2、可以先用命令行来测试绑核运行
1)先确定需绑核线程的线程ID(TID),可通过adb查到TID:
可以先用ps命令查看应用的进程号PID,然后通过top命令查到当前进程下的所有线程TID:
ps -A | grep <包名>
top -p <PID> -H
上图中5683这个进程下有3个线程,其中TID:5693这个线程在主要消耗CPU资源
2)查看当前线程的CPU执行核心的掩码(每个线程都会有一个系统分配的TID,注意这个不是相对当前进程来说的线程ID,是相对系统而言的线程ID,Android程序可通过android.os.Process.myTid()接口来获取线程的TID)
taskset -p <TID>
将指定TID绑定到指定核上命令:
taskset -p <掩码> <TID>
此命令的关键在于掩码怎么来,它需要指定一个16进制的数值(不用写0x)。假设现在是一个8核4大核+4小核的CPU架构,需要绑哪个核运行就要将哪个核的二进制位改成1:
cpu7 cpu6 cpu5 cpu4 cpu3 cpu2 cpu1 cpu0
大核4 大核3 大核2 大核1 小核4 小核3 小核2 小核1
这个排列其实就是步骤1中查到的核心分布信息,之所以CPU0在最右边,是因为二进制低位在右边,高位在左边,所以我们在算掩码时的CPU核心的排列就是从右向左CPU0、CPU1...依次递增
绑4个大核
1 1 1 1 0 0 0 0
得到的掩码值就是f0
绑3、4大核和1、2小核
1 1 0 0 0 0 1 1
得到的掩码值就是c3
所以如果我们要绑定在4个大核上运行,则执行下面的命令:
taskset -p f0 <TID>
执行完绑核命令后,可以再执行taskset命令查看当前线程TID运行的核心分布,确认绑核运行是否成功
注意,通过实测发现,当我们绑定多个大核时,我们查询到的核心分布可能只会有一个大核的情况,猜测应该是大核会不定时关核休眠,以此降低功耗。比如我们指定的是f0,实际查到可能会是10、b0。
3、Android程序中可通过JNI调用c++实现绑核,c++绑核代码如下
extern "C"
JNIEXPORT jint JNICALL
Java_com_android_demo_MainActivity_bindCpu(JNIEnv *env, jobject thiz, jint tid) {
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(4, &mask);
CPU_SET(0, &mask);
CPU_SET(1, &mask);
CPU_SET(2, &mask);
if (sched_setaffinity(tid, sizeof(mask), &mask) == -1) {
LOGI("Error setting CPU affinity: %s\n", strerror(errno));
return -1;
}
return 0;
}
上面代码关键在于CPU_SET()函数的第一个参数,这个是指定线程需要运行到哪个核上的,这里的数值实际就是步骤1中查到的CPU核心序号。
然后就是sched_setaffinity()这个函数,第一个参数是指定线程TID,其他代码照搬即可,函数返回值是-1表示绑定失败,否则就是成功。
代码执行完后也可通过taskset命令查询线程运行CPU核心情况。
最后补充,调用c++执行绑核的应用不用声明成系统应用也是可以的,对CPU资源占用要求不高的线程不用绑核,系统默认分配即可,对CPU资源占用高的线程可绑定大核运行,比如车载语音降噪进程/线程。