应用进程、线程设置亲核性
方法一:使用taskset命令
在 Linux/Android 系统中,每个线程都有自己唯一的 ID,我们通常称之为 TID 或 LWP (Light-weight Process ID)。taskset 命令既可以对整个进程(使用 PID),也可以对进程中的特定线程(使用 TID)进行操作。
查询应用线程的 CPU 亲和性
-
查找进程 PID 这一步和之前一样,首先找到你的目标应用所在的进程 PID。
adb shell ps -A | grep your.app.package.name假设我们找到的 PID 是
1234。 -
查找目标线程的 TID 使用
ps -T命令可以列出指定进程(-p <PID>)下的所有线程及其 TID。adb shell ps -T -p 1234输出结果会是类似下面这样:
USER PID TID VSIZE RSS WCHAN ADDR S NAME u0_a123 1234 1234 2582964 123456 SyS_epoll_wait 0 your.app.package.name <-- 主线程,TID通常等于PID u0_a123 1234 1255 2582964 123456 futex_wait_queue_me 0 Jit thread pool u0_a123 1234 1256 2582964 123456 futex_wait_queue_me 0 HeapTaskDaemon u0_a123 1234 1258 2582964 123456 SyS_epoll_wait 0 RenderThread <-- 这是渲染线程 ...在这个输出中:
PID列显示的是主进程 ID。TID列显示的是每个线程各自的 ID。NAME列是线程的名称,可以帮助你识别目标线程(例如RenderThread、AudioThread或你自己命名的线程)。
你需要从这里找到你关心的那个线程的 TID。例如,我们想查询
RenderThread的亲和性,它的 TID 是1258。 -
使用 TID 查询亲和性
taskset的-p参数既可以接受 PID 也可以接受 TID。现在我们用获取到的 TID 来查询。adb shell taskset -p 1258输出会显示该线程的 CPU 亲和性掩码,例如:
pid 1258's current affinity mask: f0解读掩码
f0(假设是8核CPU):f0(十六进制) =11110000(二进制)- 这意味着 TID 为
1258的这个线程被允许在 CPU 4, CPU 5, CPU 6, 和 CPU 7 上运行。这在很多安卓设备上很常见,系统会将渲染线程这类对性能敏感的任务调度到大核(Performance Cores)上。
设置应用线程的 CPU 亲和性
设置线程亲和性的步骤和查询类似,只是命令格式略有不同。
-
获取 PID 和 TID 按照上面的步骤,先找到目标应用的 PID,再找到目标线程的 TID。假设 TID 仍然是
1258。 -
使用 TID 设置亲和性 使用
taskset -p <mask> <TID>的格式来设置。adb shell taskset -p <mask> <TID>示例: 假设我们有一个 8 核的 CPU,我们想把 TID 为
1258的RenderThread线程固定在 CPU 7 这一个性能最强的核心上运行。-
首先计算掩码:
- 只在 CPU 7 上运行,二进制掩码是
10000000 - 转换为十六进制就是
80
- 只在 CPU 7 上运行,二进制掩码是
-
执行命令:
adb shell taskset -p 80 1258
执行后,你可以立刻再次使用查询命令来验证设置是否生效:
adb shell taskset -p 1258如果成功,输出应该是:
pid 1258's current affinity mask: 80 -
总结与注意事项:
- 核心区别: 操作进程用 PID,操作线程用 TID。
- 如何找TID:
adb shell ps -T -p <PID>是关键命令。 - 命令通用性:
taskset -p命令对 PID 和 TID 都有效。 - Root 权限: 和操作进程一样,修改线程的亲和性通常也需要 root 权限 (
adb root)。 - 线程生命周期: 线程是由应用动态创建和销毁的。如果你要操作的线程退出了,它的 TID 就会失效。你需要确保在操作时,该线程是存活的。
- 性能影响: 对线程(尤其是像
RenderThread这样的关键系统线程)的亲和性进行不当修改,可能会对应用的流畅度和响应性产生非常直接且负面的影响。请谨慎测试和使用。
方法二:通过进程运行信息方式
-
查找进程 PID 这一步和之前一样,首先找到你的目标应用所在的进程 PID。
adb shell ps -A | grep your.app.package.name假设我们找到的 PID 是
1234。 -
查找目标线程的 TID 使用
ps -T命令可以列出指定进程(-p <PID>)下的所有线程及其 TID。adb shell ps -T -p 1234 | grep "xxx"
cat /proc/26207/task/26289/status
Name: TaskStackChange
Umask: 0077
State: S (sleeping)
Tgid: 26207
Ngid: 0
Pid: 26289
PPid: 1227
TracerPid: 0
Uid: 10137 10137 10137 10137
Gid: 10137 10137 10137 10137
FDSize: 512
Groups: 1077 3001 3002 3003 3007 9997 20137 50137
VmPeak: 17452596 kB
VmSize: 17157476 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 606676 kB
VmRSS: 215616 kB
RssAnon: 89884 kB
RssFile: 111072 kB
RssShmem: 14660 kB
VmData: 2071176 kB
VmStk: 8192 kB
VmExe: 8 kB
VmLib: 171360 kB
VmPTE: 2568 kB
VmSwap: 74048 kB
CoreDumping: 0
THP_enabled: 1
Threads: 84
SigQ: 0/20307
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000080001204
SigIgn: 0000000000000001
SigCgt: 0000006f400084f8
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000000000000000
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 2
Seccomp_filters: 1
Speculation_Store_Bypass: thread vulnerable
//重点在这里
Cpus_allowed: ff
Cpus_allowed_list: 0-7
Mems_allowed: 1
Mems_allowed_list: 0
voluntary_ctxt_switches: 5589
nonvoluntary_ctxt_switches: 15019