Published at 2024-02-15 | Last Update 2024-02-15
整理一些 Linux 服务器性能相关的 CPU 硬件基础及内核子系统知识。
水平有限,文中不免有错误或过时之处,请酌情参考。
对于 Linux 机器,可以用 lscpu
、cat /proc/info
等命令查看它的 CPU 信息,
比如下面这台机器,
$ lscpu
Architecture: x86_64
CPU(s): 48
On-line CPU(s) list: 0-47
Thread(s) per core: 2
Core(s) per socket: 12
Socket(s): 2
NUMA node(s): 2
Model: 63
Model name: Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
NUMA node0 CPU(s): 0-11,24-35
NUMA node1 CPU(s): 12-23,36-47
...
看到有 48 个 CPU。 要理解这些 CPU 在物理上是怎么分布的(layout),需要先熟悉几个概念。
Package
如下图,package(直译为“封装”)是我们能直接在主板上看到的一个东西,
Fig. CPU package Image source
里面封装一个或多个处理器核心(称为 core 或 processor)。
Core
(processor)本文的 “core/processor” 都是指硬件核心/硬件处理器。一个 package 里面可能会包含多个处理器,如下图所示,
Fig. Cores/processors in a package Image source
或者从芯片视图看:
Fig. Cores/processors in a package Image source
Fig. Hyper-threading Image source
大部分 X86 处理器都支持超线程,也叫硬件线程。 如果一个 CORE 支持 2 个硬件线程, 那么启用超线程后, 这个 CORE 上面就有 2 个在大部分情况下都能独立执行的指令流(这 2 个硬件线程共享 L1 cache 等), 操作系统能看到的 CPU 数量会翻倍(相比 CORE 的数量), 每个 CPU 对应的不是一个 CORE,而是一个硬件线程/超线程(hyper-thread)。
CPU
以上提到的 package、core/processor、hyper-threading/hardware-thread,都是硬件概念。
在任务调度的语境中,我们所说的 “CPU” 其实是一个逻辑概念。 例如,内核的任务调度是基于逻辑 CPU 来的,
逻辑 CPU 的数量和分布跟 package/core/hyper-threading 有直接关系, 一个逻辑 CPU 不一定对应一个独立的硬件处理器。
下面通过一个具体例子来看下四者之间的关系。
cpupower/hwloc/lstopo
查看三者的关系还是本文最开始那台 Intel CPU 机器,Thread(s) per core: 2
说明它启用了超线程/硬件线程。另外,我们通过工具 cpupower
来看下它的 CPU 分布,
$ cpupower monitor
| Mperf
PKG|CORE| CPU| C0 | Cx | Freq
0| 0| 0| 2.66| 97.34| 2494
0| 0| 24| 1.89| 98.11| 2493
0| 1| 1| 2.09| 97.91| 2494
0| 1| 25| 1.77| 98.23| 2494
...
0| 13| 11| 1.95| 98.05| 2493
0| 13| 35| 2.30| 97.70| 2492
1| 0| 12| 1.65| 98.35| 2493
1| 0| 36| 1.58| 98.42| 2494
...
1| 13| 23| 1.78| 98.22| 2494
1| 13| 47| 5.07| 94.93| 2493
前三列:
PKG
:package,
2 个独立的 CPU package(0~1
),对应上面的 NUMA;
CORE
:物理核心/物理处理器
每个 package 里 14 个 CORE(0~13
);
CPU
:用户看到的 CPU,即我们上面所说的逻辑 CPU
这台机器启用了超线程(hyperthreading),每个 CORE 对应两个 hardware thread
,
每个 hardware thread 最终呈现为一个用户看到的 CPU,因此最终是 48 个 CPU(0~47
)。
也可以通过 hw-loc
查看硬件拓扑,里面能详细到不同 CPU 的 L1/L2 cache
关系:
$ hwloc-ls
Machine (251GB total)
NUMANode L#0 (P#0 125GB)
Package L#0 + L3 L#0 (30MB) # <-- PKG 0
L2 L#0 (256KB) + L1d L#0 (32KB) + L1i L#0 (32KB) + Core L#0 # <-- CORE 0
PU L#0 (P#0) # <-- Logical CPU 0 对应到这里
PU L#1 (P#24) # <-- Logical CPU 24 对应到这里
L2 L#1 (256KB) + L1d L#1 (32KB) + L1i L#1 (32KB) + Core L#1 # <-- CORE 1
PU L#2 (P#1) # <-- Logical CPU 1 对应到这里
PU L#3 (P#25) # <-- Logical CPU 25 对应到这里
...
NUMANode L#1 (P#1 126GB) + Package L#1 + L3 L#1 (30MB)
L2 L#12 (256KB) + L1d L#12 (32KB) + L1i L#12 (32KB) + Core L#12
PU L#24 (P#12)
PU L#25 (P#36)
...
L2 L#23 (256KB) + L1d L#23 (32KB) + L1i L#23 (32KB) + Core L#23
PU L#46 (P#23)
PU L#47 (P#47)
如无特殊说明,本文接下来的 “CPU” 都是指逻辑 CPU, 也就是 Linux 内核看到的 CPU。
P-State
(processor performance state):处理器支持的 voltage-freq
列表处理器可以工作在不同的频率,对应不同的电压(最终体现为功耗)。这些 voltage-frequency 组合就称为 P-State(处理器性能状态)。 比如下面这个 P-State Table
Voltage | Frequency |
---|---|
1.21 V | 2.8 GHz (HFM) |
1.18 V | 2.4 GHz |
1.05 V | 2.0 GHz |
0.96 V | 1.6 GHz |
0.93 V | 1.3 GHz |
0.86 V | 600 MHz (LFM) |
这个 table 会保存在一个名为 MSR
(model specific register)
的 read-only 寄存器中。
p-state
中的最低和最高频率p-state table 中,
base frequency
):市场宣传术,其实就是 p-state 中的最高频率上面介绍了根据 p-state 的定义,处理器的最低(LF)和最高(HF)频率,这些都是很好理解的技术术语。
但在市场宣传中,厂商将 HF —— p-state 中的上限频率 —— 称为基础频率或基频(Base Frequency),给技术人造成了极大的困惑。
overclocking
):运行在比基频更高的频率既然敢将 HF 称为基频,那处理器(至少在某些场景下)肯定能工作在更高的频率。 根据 wikipedia,
结合我们前面的术语,这里说的“官方认证的最高稳定频率”就是基频(HF), 工作在基频以上的场景,就称为超频。比如基频是 2.8GHz,超频到 3.0GHz。
Intel Turbo
(睿频) 或 AMD PowerTune
:动态超频Turbo 是 Intel 的技术方案,其他家也都有类似方案,基本原理都一样:根据负载动态调整频率 —— 但这句话其实只说对了一半 —— 这项技术的场景也非常明确,但宣传中经常被有意或无意忽略: 在部分处理器空闲的情况下,另外那部分处理器才可能动态超频。
所在官方文档说,我们会看到它一般都是写“能支持的最大单核频率”(maximum single-core frequency
)
叫 Max Turbo Frequency,因为它们在设计上就不支持所有核同时运行在这个最大频率。
原因其实也很简单: 频率越高,功耗越高,散热越大。整个系统软硬件主要是围绕基频(HF)设计和调优的, 出厂给出的也是和基频对应的功耗(TDP,后面会介绍)。 另外,TDP 也是数据中心设计时的主要参考指标之一,所以大规模长时间持续运行在 TDP 之上, 考验的不止是处理器、主板、散热片这些局部的东西,数据中心全局基础设施都得跟上。
下面看个具体处理器 turbo 的例子。
下面是一个 Intel 处理器官方参数,
Turbo Freq and corresponding Active Cores Image source
解释一下,
3.6GHz
,SSE/AVX/...
)也有关系能超到多少,跟跑的业务类型(或者说使用的指令集)也有关系,使用的指令集不同,能达到的最高频率也不同。 比如,
Mode | Example Workload | Absolute Guaranteed Lowest Frequency |
Absolute Highest Frequency |
---|---|---|---|
Non-AVX | SSE, light AVX2 Integer Vector (non-MUL), All regular instruction | Base Frequency | Turbo Frequency |
AVX2 Heavy | All AVX2 operations, light AVX-512 (non-FP, Int Vect non-MUL) | AVX2 Base | AVX2 Turbo |
AVX-512 Heavy | All heavy AVX-512 operations | AVX-512 Base | AVX-512 Turbo |
另外,在一些 CPU data sheet 中,还有一个所谓的 all-core turbo
:
这是所有 core 同时超到同一个频率时,所能达到的最高频率。这个频率可能比 base 高一些,
但肯定比 max turbo frequency 低。例如,Xeon Gold 6150
lscpu/procinfo
实际查看各种频率老版本的 lscpu
能看到三个频率指标:
$ lscpu
...
Model name: Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz
CPU MHz: 2494.374 # 实际运行频率,但不准,因为每个 CORE 可能都运行不同频率
CPU max MHz: 2500.0000 # max turbo freq
CPU min MHz: 1200.0000 # p-state low-freq
新版本的 lscpu
去掉了 CPU MHz
这个字段,每个 CORE 都可能工作在不同频率,
这种情况下这个字段没什么意义。要看每个 CORE/CPU 的实时工作频率,
# CPU info: Intel(R) Xeon(R) Gold 5318Y CPU @ 2.10GHz
$ cat /proc/cpuinfo | egrep '(processor|cpu MHz)'
processor : 0
cpu MHz : 2100.000
processor : 1
cpu MHz : 2100.000
processor : 2
cpu MHz : 2100.000
processor : 3
cpu MHz : 2600.000
...
processor : 51
cpu MHz : 2100.000
...
TDP
(Thermal Design Power):Base Freq 下的额定功耗TDP 表示的处理器运行在基频时的平均功耗(average power)。
这就是说,超频或 turbo 之后,处理器的功耗会比 TDP 更大。 具体到实际,需要关注功耗、电压、电流、出风口温度等等指标。 这些内容后面再专门讨论。
以 AMD 的 turbo 技术为例:
Fig. Architecture of the PowerTune version Image source
服务器启动过程中的硬件初始化,可以配置一些硬件特性。运行在内核启动之前。