ARM cpufreq(DVFS)¶
DVFS简介¶
在ARM系统中cpufreq子系统允许动态调节电压和CPU频率(dynamic voltage and frequency scaling, DVFS),可以影响CPU性能以及电能消耗以适应当前工作负载。
检查CPU系统¶
通过 /proc/cpuinfo
可以查看CPU信息,例如 树莓派Raspberry Pi 4 上执行 cat /proc/cpuinfo
可以看到如下输出:
processor: 0
BogoMIPS: 108.00
Features: fp asimd evtstrm crc32 cpuid
CPU implementer: 0x41
CPU architecture: 8
CPU variant: 0x0
CPU part: 0xd08
CPU revision: 3
processor: 1
...
processor: 2
...
processor: 3
...
Hardware: BCM2835
Revision: b03112
Serial: 100000003b6824d7
Model: Raspberry Pi 4 Model B Rev 1.2
这里 processors
后面的数字表示当前内核的CPU编号,例如 processor: 1
对应的 /sys/
目录下处理器 /sys/devices/system/cpu/cpu1
CPU part
是从 MIDR_EL1
系统寄存器中读取的CPU主型号,需要查询处理器的技术参考手册来找到对应的部件号,例如:
0xd03
表示Cortex-A53
0xd07
表示Cortex-A57
- NVIDIA Jetson 使用的CPU0xd08
表示Cortex-A72
- 树莓派Raspberry Pi 4 使用的CPU
备注
在Android手机上执行 cat /proc/cpuinfo
通常会看到多核心采用了不同的处理器架构,也就是常说的大小核。
对于 Jetson Nano 处理器:
processor: 0 model name: ARMv8 Processor rev 1 (v8l) BogoMIPS: 38.4 0 Features: fp asimd evtstrm aes pmull sha1 sha2 crc32 CPU implementer : 0x41 CPU architecture: 8 CPU variant: 0x1 CPU part: 0xd07 CPU revi sion: 1
将进程绑定(pinning)到CPU¶
在Linux中,每个进程的亲和性(affinity)描述了进程在SMP系统中将运行在哪个CPU上,默认是所有CPU,但是我们可以通过 taskset
命令来修改亲和性。
以下案例将
ls /lib
只运行在CPU 5上(Contex_A53_4):taskset -c 5 ls /lib
以下案例则只在CPU 1和2上运行(两个Cortex-A57核心):
taskset -c 1,2 grep -i joe users.txt
以下案例在所有CPU(0-5)上运行命令:
taskset -c 0-5 ping 192.0.0.1
动态电压和频率调整¶
动态电压和频率调整(Dynamic Voltage and Frequency Scaling, DVFS)技术可以运行时调整CPU的时钟频率,通过降低时钟频率可以使得处理idle并且降低电能消耗和热量产生。
查看当前CPU 3的时钟频率:
cat /sys/devices/system/cpu/cpu3/cpufreq/scaling_cur_freq
例如 树莓派Raspberry Pi 4 显示600MHz的低压节电频率:
600000
可以检查CPU支持的可用频率:
cat /sys/devices/system/cpu/cpu3/cpufreq/scaling_available_frequencies
例如 树莓派Raspberry Pi 4 显示出有4档处理器频率:
600000 750000 1000000 1500000
手动调整CPU 3的频率:
echo 1000000 > /sys/devices/system/cpu/cpu3/cpufreq/scaling_setspeed
这里遇到报错:
-bash: echo: write error: Invalid argument
这个报错参考 /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed: Invalid argument 的解释:
sysfs
和 procfs
是内核的接口,通过读写这些分拣来和内核中驱动交互。通常出现 permission denied
则是文件系统权限不足,但是这里的返回是 invalid argument
表明是驱动返回这个错误,很可能是写入数据是驱动不支持的数值范围。
经过测试,我发现树莓派 Raspberry Pi 4不是所有CPU核心都支持 echo
某个CPU频率到 scaling_setspeed
,对于 CPU0
和 CPU1
是支持该指令参数,但是 CPU2
和 CPU3
则不支持。但是,我测试下来即使 echo
指定CPU频率值,例如 echo 1000000 /sys/devices/system/cpu/cpu1/cpufreq/scaling_setspeed
,但是读取 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
值依然不是设定值。
Scaling governor(主频调节)¶
内核动态调节主频的规则是通过 cpufreq scaling governor 定义的。
cpu频率调节策略定义了系统CPU的电源管理特性,会直接影响到CPU性能。每个调节策略有自己独特的特性和用途,适合不同的应用环境。
处理器支持的cpu频率调节策略可以通过以下命令检查:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
对于 树莓派Raspberry Pi 4 有以下cpu频率调节策略:
conservative ondemand userspace powersave performance schedutil
检查当前cpu频率调节策略:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
可以看到默认是按需:
ondemand
上述按需cpu频率策略,在idle时候,cpu频率就是最低的600MHz,我们可以通过:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
看到输出是:
600000
我们可以调整策略成性能优先:
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
然后检查策略:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
输出确实是性能优先:
performance
备注
在 树莓派Raspberry Pi 4 和 Jetson Nano 上4个CPU核心的cpu频率调节策略是完全同步的,也就是修改 cpu0 的调节策略会立即在其他cpu核心同步生效。
现在我们检查CPU当前核心频率:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
可以看到飙升到最高频率:
1500000
我在 Jetson Nano 上调整 scaling_governor
设置成 performance
之后,频率从原先 518400
上升到 1479000
不过设置cpufreq scaling governor为performance可能会带来CPU温度上升。
备注
我在 Raspberry Pi Cluster 中组建 Kubernetes Atlas 集群,希望能够尽可能压榨出处理器性能,所以我设置 governor 都是 performance
。注意,需要配备好散热风扇,并且部署好监控,随时应对处理器国人风险。
governor系统配置¶
虽然可以通过 rc.local
这样的启动脚本来人为设置处理器运行策略,但是最好的方式还是采用系统发行版约定熟成的配置方式。所以,在Ubuntu中,可以采用如下方法:
sudo apt-get install cpufrequtils
echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils
sudo systemctl disable ondemand
备注
CPU电源管理对系统性能影响重大,在服务器运维领域,我需要系统学习和整理