2.8.2 CPU的拓扑结构

CPU的拓扑结构可以理解为在硬件层面上多个CPU的排列方式, 对于运行的任务而言,拓扑结构决定了其从一个CPU迁移到另一个CPU将要付出的代价。在详细讨论拓扑结构之前,我们先介绍几个与CPU相关的概念:

  • Socket: 对应主板上CPU插槽

  • Core: 独立的一个执行单元,硬件上实现真正并行计算的组件,例如我们说一个CPU是“四核八线程”,其中每个核就对应一个Core

  • Hyper-Threading: 逻辑上的一个执行单元,多个超线程共享一个核,例如“四核八线程”,就是每两个线程共享一个核。由于多个超线程共享一个物理执行单元,因此超线程并不是硬件层面上独立的并行计算单元,只是在OS级别的并发单元。

例如本人机器的CPU 型号是 Intel i5-8265U, 一个物理处理器,4核8线程,其拓扑结果如下:

Linux 中通过命令 lstopo 即可查看CPU 的拓扑结构,通过命令 hardinfo 可以查看系统的各类硬件信息。

这里我们并没有提及CPU, CPU是最早出现的概念,早期与Socket是1:1的对应关系,但发展到现在基本已经是一个泛化和抽象的概念了,严格地说已经变成了一个日常用语。但在OS层面,CPU依然表示系统的一个执行单位,每个线程都会对应一个系统CPU. 例如上图中,系统会显示有8个CPU.

Note: 系统CPU 的信息记录在 /proc/cpuinfo 中,可以通过 cat 命令查看。

通过该图可以发现:P#0与P#4就是两个超线程,并且共享Core L#0. 还可以看出同一个Core中的所有超线程共享所有的CPU缓存(L1, L2, L3),而不同的Core 只共享L3。

对多核CPU而言,如何访问主存(RAM)也是一个重要议题,主要涉及到两种拓扑结构:

  • SMP(Symmetric Multiprocessing) 被译为对称多处理, 简单说就是每个CPU在访问主存时的代价都是一样的,主存作为全局的一个资源被所有CPU所共享。示意图如下:

  • NUMA(Non-uniform Memory Access) 被译为非均匀访存模型, 系统将CPU分为不同的集群,每个集群叫着一个节点(Node),每个节点都有自己的本地内存(Local RAM),CPU 可以访问任何节点的内存,但访问本地内存的速度要远高于访问非本地内存的速度。示意图如下:

在图一中,所有的CPU 都处在一个NUMA节点中。

当CPU访问数据时,只有当所有的缓存(L1, L2, L3)都没有命中时才会访问主存(RAM),如果主存也没有数据则会发生缺页中断(page fault)并从磁盘加载数据。通过上面的介绍我们知道:从缓存到主存,不同的CPU能够共享的层级是不一样的。也就是说,当迁移任务时,选择不同的目标CPU 就意味着要付出不同的代价。通常而言我们认为:

  1. 同一个超线程集(Hyperthreaded Set)中的CPU能够共享所有的缓存、主存,所以将任务在不同线程之间迁移可以认为没有性能损耗

  2. SMP架构或者同一个NUMA节点内,不同的Core 可能只会共享部分缓存,但访问主存的时间都是一样的。因此如果对任务进行跨核迁移的话,新CPU的缓存将需要重新warm up

  3. NUMA架构下,不同节点(Node)会有自己的本地主存(Local RAM),CPU访问其他节点的主存比访问本地主存需要更多时间。因此不到万不得已,调度器不会跨节点地进行任务迁移。

从同一个超线程集合,到NUMA中跨节点的CPU,我们可以认为CPU之间的“物理距离”在不断增加,这种“物理距离”形成了一种层级结构。根据上述分析可以知道,当调度器做任务迁移时,所选择的目标CPU越“近”则性能损耗就越小。因此内核需要某种方式来有效地组织CPU,这种组织方式能够根据“距离”将CPU分组,并形成合理的层级结构,使得调度器能够高效调整各个CPU的负载。

Last updated