如何实现CPU单核睿频?

之前的Blog:再谈CPU的电源管理(如何做到稳定全核睿频?)最终通过了tuned实现了CPU全核心运行在允许的全核睿频频率上。但是这个只是场景之一,并不是所有场景下都会用到很多的核心,从这些应用角度讲,更需要少量但是更高频率的核心,一个比较简单的例子就是DPDK,作为DPDK应用,一般来说也不会用到很多核心,但是他的polling模型,是希望单核频率越高越好的。针对类似的这种场景,实现少量核心,比如说单核的高频,比多核全开,频率变低更合适。

那么问题来了,怎么在Linux上实现稳定的单核睿频呢?这里给一个稍微暴力点的办法。

以我们目前机器上的CPUIntel 6240R为例,在Intel Ark 上,可以看到这款CPU的最大睿频频率是4.00 GHz,也就是说,理论上,至少有一个核心能运行在4GHz的频率上。虽然Intel没有明确说明这款CPU的全核睿频速度,但是从上次的结果看,这块CPU在全核状态,最高能达到3.2GHz的频率。

那么怎么实现单核最高频率呢?同样上一篇Blog里,在Intel论坛上有个关于C6状态的信息:”has 133 microsecond wakeup latency and turns off core (allowing more power to other cores)”,也就是说,当一个核心进入C6状态,核心就被关闭,同时也意味着有更多的电力可以给其他核心(提升频率)。

这么说就简单了,想办法让不需要的CPU核心进入C6状态,或者将核心关闭就行。这里Linux提供了一个接口,直接关闭CPU,那么理论上关闭了一些核心之后,相应的剩下的核心频率会相应提高。首先,先看看当前CPU的一些情况:

 ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                96
On-line CPU(s) list:   0-95
Thread(s) per core:    2
Core(s) per socket:    24
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 85
Model name:            Intel(R) Xeon(R) Gold 6240R CPU @ 2.40GHz
Stepping:              7
CPU MHz:               3199.951
CPU max MHz:           4000.0000
CPU min MHz:           1000.0000
BogoMIPS:              4800.00
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              1024K
L3 cache:              36608K
NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94
NUMA node1 CPU(s):     1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95

可以看到目前机器上有两颗CPU,对应的核心分别是0,2,4,6...双数核,和1,3,5,7...单数核,如果我想只保留第二颗CPU的1号核心的话,就需要执行:

for i in 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95; do echo 0 > /sys/devices/system/cpu/cpu$i/online  ;done

把所有除1之外的单数核心online状态修改成0,也就是强制这些CPU核心下线。执行之后再执行lscpu看下状态:

~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                96
On-line CPU(s) list:   0-2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94
Off-line CPU(s) list:  3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95
Thread(s) per core:    1
Core(s) per socket:    12
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 85
Model name:            Intel(R) Xeon(R) Gold 6240R CPU @ 2.40GHz
Stepping:              7
CPU MHz:               3199.804
CPU max MHz:           4000.0000
CPU min MHz:           1000.0000
BogoMIPS:              4800.00
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              1024K
L3 cache:              36608K
NUMA node0 CPU(s):     0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94
NUMA node1 CPU(s):     1

可以看到Off-line CPU(s) list:多了刚刚设置offline的核心。此时第二颗CPU只有第一个核心在线了。此时再运行一下turbostat看下核心频率:

~]# turbostat
Package Core    CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     SMI     POLL    C1      C1E     C6      POLL%   C1%     C1E%    C6%     CPU%c1  CPU%c6  CoreTmp PkgTmp  PkgWatt RAMWatt PKG_%R
AM_%
-       -       -       13      0.42    3200    2346    13230   0       26      19085   0       0       0.04    97.55   0.00    0.00    99.58   0.00    58      56      38.96   43.47   0.00 0
.00
0       0       1       67      1.68    4000    2394    978     0       10      1128    0       0       0.00    98.33   0.00    0.00    98.32   0.00    55      56      38.96   43.47   0.00 0
.00
0       0       48      3       0.09    3200    2394    307     0       0       381     0       0       0.00    99.91   0.00    0.00    99.91
0       1       4       15      0.46    3200    2394    613     0       0       985     0       0       0.00    99.55   0.00    0.00    99.54   0.00    56
0       1       52      169     5.30    3200    2394    655     0       0       507     0       0       0.00    94.70   0.00    0.00    94.70
0       2       8       9       0.29    3200    2394    300     0       0       558     0       0       0.00    99.71   0.00    0.00    99.71   0.00    56
0       2       56      5       0.16    3200    2394    183     0       0       214     0       0       0.00    99.84   0.00    0.00    99.84
...

可以看到CPU 1非常突出,在许多3200中的4000特别亮眼,说明成功的将单核频率拉到了Ark描述的4.0GHz,说明Intel没有骗人,嘿嘿。

到这里任务算是完成了,实际上Intel的睿频状态比较多,不同的核心数量,会获得不一样的频率,具体的,可以根据情况测试。最后还有一件事,就是如何恢复呢,自然也很简单:重启机器,或者反向执行一下脚本:

for i in 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 95; do echo 1 > /sys/devices/system/cpu/cpu$i/online  ;done