【前言】
写了一段时间博客发现,以实际例子来说明一件事,可能会让读者更容易理解那些知识。
从今天开始从手机优化的案例来逐篇对算法的优化做一个简单的总结专栏。
1. 为什么需要绑核操作?
需求决定一切:
- 需要程序更快执行完成
- 需要程序避开频繁的CPU调度
- 需要屏蔽干扰条件验证算法的性能
- Power Saved
2. 如何找到我们需要的CPU核?
通过shell可以看到SOC的CPU信息:
cat proc/cpuinfo
processor : 0 ~ 7
BogoMIPS : 38.40
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0 / 0x1
CPU part : 0xd46 / 0xd47 / 0xd48
CPU revision : 0
- processor : CPU idx
- CPU implementer : CPU arch文件描述位于:cpu.h
//cpu.h
static const int ARM = 0x41;
static const int NVIDIA = 0x4e;
static const int QUALCOMM = 0x51;
...
- CPU architecture: 基于ARM公司开发的精简指令集架构的指令集架构
-
CPU part: CPU的架构,在cputype.h中描述
//arch/arm64/include/asm/cputype.h #define QCOM_CPU_PART_KRYO_7XX_SILVER 0xD46 #define QCOM_CPU_PART_KRYO_7XX_GOLD 0xD47 #define QCOM_CPU_PART_KRYO_7XX_GOLD_PLUS 0xD48
3. 如何绑核?
通常,我们会把进程绑定到大核簇或者小核簇,或者当个cpu上面,以提高程序执行效率。
硬CPU亲和性(affinity):
为啥加硬,你都开始强上了。。。Lock to CpU:
task_struct --> cpus_allowed --> 8 cpu --> 8位的位掩码
default:
如果一个进程可以在任何 CPU 上运行,并且能够根据需要在处理器之间进行迁移,那么位掩码就全是1.
cpu_set_t cpuset;
CPU_ZERO(&cpuset); //对CPU对应位置进行清0操作
CPU_SET(0, &cpuset); //0: 对需要绑定的CPU设置
sched_setaffinity(0, sizeof(cpuset), &cpuset) //0:代表自己pid
sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)
sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask)
绑核需要注意是,子进程会继承父进程的绑核关系。
4. 查看cpu绑定?
ps -o pid,psr,comm -p 166
PID PSR COMM
166 2 [kswapd0:0]
频率调节模式
ondemand:按需快速动态调整CPU频率, 一有cpu计算量的任务,就会立即达到最大频率运行,等执行完毕就立即回到最低频率
conservative:保守模式,类似于ondemand,但调整相对较缓
performance:性能模式,只有最高频率,不考虑消耗的电量,流畅度没得说
powersave: 省电模式,通常以最低频率运行,流畅度极低
userspace:用户自定义模式,系统将变频策略的决策权交给了用户态应用程序