IOMMU调优: CPU pinning

为了使得PCI passthroughs 更为稳定和高性能,通过 CPU pinning 可以实现 NUMA架构 让处理器访问近端 PCIe 设备提高性能,同时也可以避免 缓存踩踏 导致性能下降。

原理

KVM guest默认是运行在和虚拟机相同县城数量,这些县城由Linux调度器按照优先级和等级队列调度到任何可用的CPU核心。这种方式下,如果线程被调度到不同的物理CPU就会导致本地CPU缓存(L1/L2/L3)失效,此时会明显影响虚拟机性能。CPU pinning就是针对这种虚拟CPU分配到物理CPU上运行的问题,设置两者的映射关系,尽可能减少缓存失效。此外,现代CPU通常使用一种共享的L3缓存,精心配置虚拟CPU和物理CPU的映射,可以使得L3缓存近端访问,降低缓存失效。

在完成 Open Virtual Machine Firmware(OMVF) 虚拟机设置添加NVMe pass-through 之后,从物理连接角度, HPE ProLiant DL360 Gen9服务器 的 PCIe 3.0 Slot 1 和 Slot 2 是和CPU 0(第一块CPU)直连的,所以最佳配置是将虚拟机的vcpu绑定到物理主机的 CPU 0 下的cpu core。

CPU拓扑

现代CPU处理器硬件都是多任务的,在Intel CPU称为超线程 hyper-threading , AMD处理器称为 SMT 。检查CPU拓扑,采用以下命令:

lscpu -e

HPE ProLiant DL360 Gen9服务器E5-2670 v3 处理器拓扑如下

XEON E5-2670 v3处理器拓扑
 1CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE    MAXMHZ    MINMHZ
 2  0    0      0    0 0:0:0:0          yes 3100.0000 1200.0000
 3  1    0      0    1 1:1:1:0          yes 3100.0000 1200.0000
 4  2    0      0    2 2:2:2:0          yes 3100.0000 1200.0000
 5  3    0      0    3 3:3:3:0          yes 3100.0000 1200.0000
 6  4    0      0    4 4:4:4:0          yes 3100.0000 1200.0000
 7  5    0      0    5 5:5:5:0          yes 3100.0000 1200.0000
 8  6    0      0    6 6:6:6:0          yes 3100.0000 1200.0000
 9  7    0      0    7 7:7:7:0          yes 3100.0000 1200.0000
10  8    0      0    8 8:8:8:0          yes 3100.0000 1200.0000
11  9    0      0    9 9:9:9:0          yes 3100.0000 1200.0000
12 10    0      0   10 10:10:10:0       yes 3100.0000 1200.0000
13 11    0      0   11 11:11:11:0       yes 3100.0000 1200.0000
14 12    1      1   12 12:12:12:1       yes 3100.0000 1200.0000
15 13    1      1   13 13:13:13:1       yes 3100.0000 1200.0000
16 14    1      1   14 14:14:14:1       yes 3100.0000 1200.0000
17 15    1      1   15 15:15:15:1       yes 3100.0000 1200.0000
18 16    1      1   16 16:16:16:1       yes 3100.0000 1200.0000
19 17    1      1   17 17:17:17:1       yes 3100.0000 1200.0000
20 18    1      1   18 18:18:18:1       yes 3100.0000 1200.0000
21 19    1      1   19 19:19:19:1       yes 3100.0000 1200.0000
22 20    1      1   20 20:20:20:1       yes 3100.0000 1200.0000
23 21    1      1   21 21:21:21:1       yes 3100.0000 1200.0000
24 22    1      1   22 22:22:22:1       yes 3100.0000 1200.0000
25 23    1      1   23 23:23:23:1       yes 3100.0000 1200.0000
26 24    0      0    0 0:0:0:0          yes 3100.0000 1200.0000
27 25    0      0    1 1:1:1:0          yes 3100.0000 1200.0000
28 26    0      0    2 2:2:2:0          yes 3100.0000 1200.0000
29 27    0      0    3 3:3:3:0          yes 3100.0000 1200.0000
30 28    0      0    4 4:4:4:0          yes 3100.0000 1200.0000
31 29    0      0    5 5:5:5:0          yes 3100.0000 1200.0000
32 30    0      0    6 6:6:6:0          yes 3100.0000 1200.0000
33 31    0      0    7 7:7:7:0          yes 3100.0000 1200.0000
34 32    0      0    8 8:8:8:0          yes 3100.0000 1200.0000
35 33    0      0    9 9:9:9:0          yes 3100.0000 1200.0000
36 34    0      0   10 10:10:10:0       yes 3100.0000 1200.0000
37 35    0      0   11 11:11:11:0       yes 3100.0000 1200.0000
38 36    1      1   12 12:12:12:1       yes 3100.0000 1200.0000
39 37    1      1   13 13:13:13:1       yes 3100.0000 1200.0000
40 38    1      1   14 14:14:14:1       yes 3100.0000 1200.0000
41 39    1      1   15 15:15:15:1       yes 3100.0000 1200.0000
42 40    1      1   16 16:16:16:1       yes 3100.0000 1200.0000
43 41    1      1   17 17:17:17:1       yes 3100.0000 1200.0000
44 42    1      1   18 18:18:18:1       yes 3100.0000 1200.0000
45 43    1      1   19 19:19:19:1       yes 3100.0000 1200.0000
46 44    1      1   20 20:20:20:1       yes 3100.0000 1200.0000
47 45    1      1   21 21:21:21:1       yes 3100.0000 1200.0000
48 46    1      1   22 22:22:22:1       yes 3100.0000 1200.0000
49 47    1      1   23 23:23:23:1       yes 3100.0000 1200.0000

按照 NUMA架构 执行:

numactl -H

HPE ProLiant DL360 Gen9服务器E5-2670 v3 处理器NUMA结构如下

XEON E5-2670 v3处理器NUMA
 1available: 2 nodes (0-1)
 2node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 24 25 26 27 28 29 30 31 32 33 34 35
 3node 0 size: 32093 MB
 4node 0 free: 30201 MB
 5node 1 cpus: 12 13 14 15 16 17 18 19 20 21 22 23 36 37 38 39 40 41 42 43 44 45 46 47
 6node 1 size: 32250 MB
 7node 1 free: 29059 MB
 8node distances:
 9node   0   1
10  0:  10  21
11  1:  21  10

请注意:

  • 默认开启了超线程,所以一个CPU核心对应了2个超线程,为了最大化存储性能,需要将负载高的存储虚拟机分配到不同到CPU核心(超线程不冲突)

  • 物理服务器上安装了2个CPU(socket), SOCKET 0 对应了CPU 0, SOCKET 1 对应了CPU 1,也就是 node 0node 1 ; 在 numactl -H 输出中可以清晰看到:

    node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 24 25 26 27 28 29 30 31 32 33 34 35
    node 1 cpus: 12 13 14 15 16 17 18 19 20 21 22 23 36 37 38 39 40 41 42 43 44 45 46 47
    
  • 由于 HPE ProLiant DL360 Gen9服务器 只在 Slot 1 提供了 PCIe bifurcation ,所以我把2块 三星PM9A1 NVMe存储 通过NVMe扩展卡安装在 Slot 1 ,把第3块 三星PM9A1 NVMe存储 安装在 Slot 2 。这意味着,服务器的3块NVMe存储都是直接和 node 0 连接的,所以对应虚拟机也要 pinning 到这个 CPU 0 上,也就是CPU超线程 0 - 1124 - 35 。这两组CPU超线程实际上对应的物理CPU core一共是12个。

  • 我分配的 z-b-data-X 虚拟机共3个,采用 4c8g 规格,分配到 CPU 超线程 24 - 35 可以确保不重合,性能最大化

配置cpu pinning

  • 修订 z-b-data-1 (举例)

    sudo virsh edit z-b-data-1
    

设置 vcpucpuset 对应映射关系:

<vcpu placement='static'>4</vcpu>
<cputune>
  <vcpupin vcpu='0' cpuset='24'/>
  <vcpupin vcpu='1' cpuset='25'/>
  <vcpupin vcpu='2' cpuset='26'/>
  <vcpupin vcpu='3' cpuset='27'/>
</cputune>

参考