Linux cpu 親緣性 綁核

前言

https://www.cnblogs.com/studywithallofyou/p/17435497.html
https://www.cnblogs.com/studywithallofyou/p/16695550.html
上面的文章提到了一些相關的知識,本篇單獨針對CPU進行詳細講解。

CPU構造

CPU Central Processing Unit CPU Package

這個一般指的是整個CPU,包括包裝運行單元,控制單元,緩衝等。

比如下面Intel 80486DX2正反面

正面是一個金屬殼,用於散熱
反面是很多針腳,用於傳遞數據


CPU Socket CPU插槽

這個就是指主板上有幾個可以插CPU的地方,比如下面,就有兩個

Non-uniform memory access NUMA Node

爲了處理多CPU訪問內存的問題,提出了NUMA架構,就是把不同的CPU做區分,分配不同的內存通道。Node訪問自己所屬的內存(也叫local memory)速度比較快,訪問另一個Node的內存(也叫做remote memory)相對就慢一些。

正常情況NUMA Node與CPU Socket數量是一致的,一個插槽上插一個CPU,一個CPU分配一個NUMA Node。不過也有不一致的情況。

UMA

計算機一開始的架構是UMA:多個Processor使用同一個bus總線訪問內存,大家是平等的。後來隨着CPU核心增多,總線成爲了瓶頸,就把Processor分組,各自訪問一塊內存,變成了NUMA(非一致性內存訪問)。

NUMA與MySQL

Linux默認會啓用NUMA,讓程序儘可能申請local內存,如果超過了local內存,就會頻繁的swap。

如果是佔用內存比較大的程序,需要確保開啓NUMA後,local內存足夠,不然會導致性能抖動或者下降。

如果MySQL使用內存大於local memory的解決方案:

  • 設置綁定策略,讓MySQL可以使用所有內存
  • MySQL也有相關配置,應對這個場景。需要確認使用版本是否有該功能,如果沒有,需要下載最新的,或者編譯對應版本,在編譯是開啓對NUMA的支持。

Processor Die CPU Die 處理器芯片

Die就是指從晶圓上切下來的一個個小方塊,後續通過光刻機,刻上晶體管,形成core。

一個Die上可以擁有多個core。

Processor core

Processor core是一個獨立的單元,可以與其他core並行運算。

Integrated Circuit IC 集成電路

一個或多個Die加上一些緩存、集成顯卡組成一塊集成電路

Printed Circuit Board PCB 印刷電路板

集成電路被安裝在印刷電路版上。印刷電路板和外殼等組成一塊CPU。

如下圖,這是一塊CPU,外面綠色的是印刷電路板,中間兩個突起的方塊是Die,一個Die有兩個Core,那麼這個CPU就是雙核四核心(我們經常說的)。

一個Die打開如下圖,中間分開,上下對稱,用晶體管實現了兩個core

總結

由於CPU的設計,對不同資源做了區分,所以在高性能程序開發中,需要配置,保證最大化利用系統資源。

讓一個進程綁定在同一個core或者同一個Node下的core上,保證CPU緩存命中率,避免使用remote memory,避免上下文切換。

具體使用思路:把需要高性能運行的進程綁定到一個(一組core)上,把其他進程綁定到其他core上,避免其他進程在高性能進程佔用的core上運行,使得高性能進程綁定的core只運行一個進程,避免其他進程打擾,避免緩存丟失,避免上下文切換,提高性能。

https://en.wikipedia.org/wiki/Central_processing_unit
https://www.cc.ntu.edu.tw/chinese/epaper/0015/20101220_1508.htm
https://superuser.com/questions/324284/what-is-meant-by-the-terms-cpu-core-die-and-package
https://en.wikipedia.org/wiki/Die_(integrated_circuit)

查看cpu信息

lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                12 core個數
On-line CPU(s) list:   0-11 在線core個數
Thread(s) per core:    1 每個物理core可以有幾個thread。是否可以多個任務併發進行。邏輯核。用指令把一個物理core再分成兩個或多個併發運行,提高使用率。
Core(s) per socket:    6 每個插槽上的cpu有幾個core
Socket(s):             2 有幾個插槽,主板上插了幾塊cpu
NUMA node(s):          2 有幾個node,一般一個socket分成一個node
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 45
Stepping:              7
CPU MHz:               1200.000
BogoMIPS:              3999.45
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              15360K
NUMA node0 CPU(s):     0-5 每個node上core編號
NUMA node1 CPU(s):     6-11

查看numa內存分配

numactl --hardware
available: 2 nodes (0-1) 兩個numa node,0和1
node 0 cpus: 0 1 2 3 4 5 node0包含0 1 2 3 4 5core
node 0 size: 8162 MB node0 local內存大小
node 0 free: 1855 MB
node 1 cpus: 6 7 8 9 10 11
node 1 size: 8192 MB
node 1 free: 4611 MB
node distances: node和local內存/remote內存距離關係
node   0   1  
  0:  10  20  node0訪問node0的內存是10,訪問node1的內存是20(性能下降一倍)
  1:  20  10  node1訪問node0的內存是20,訪問node1的內存是10

libc

獲取系統CPU核心數

sysconf

       #include <unistd.h>

       long sysconf(int name);
        - _SC_NPROCESSORS_CONF
              The number of processors configured.  See also
              get_nprocs_conf(3).

        - _SC_NPROCESSORS_ONLN
              The number of processors currently online (available).
              See also get_nprocs(3).

一個是獲取全部的CPU核心數,一個是獲取可用的(online)核心數。也有專門的APIget_nprocs_confget_nprocs
https://man7.org/linux/man-pages/man3/sysconf.3.html

get_nprocs get_nprocs_conf

       #include <sys/sysinfo.h>

       int get_nprocs(void);
       int get_nprocs_conf(void);

https://man7.org/linux/man-pages/man3/get_nprocs_conf.3.html

mask CPU核心表示方法

linux用位掩碼(bitmask)表示每個core
0001 第一個core[core0](core編號從0開始)
0011 第一個和第二個core[core0 core1]
1000 0001 第一個和第八個core[core0 core7]

動態申請CPU core個數

cpu_set_t *CPU_ALLOC(int num_cpus);
    Allocate a CPU set large enough to hold CPUs in the range 0 to num_cpus-1. 
    申請保存指定cpu core個數(num_cpus)的mask空間。

size_t CPU_ALLOC_SIZE(int num_cpus);
    Return the size in bytes of the CPU set that would be needed to hold CPUs in the range 0 to num_cpus-1. This macro provides the value that can be used for the setsize argument in the CPU_*_S() macros 
    計算指定cpu core個數(num_cpus)的mask的長度。

void CPU_FREE(cpu_set_t *set);
    Free a CPU set previously allocated by CPU_ALLOC().

保存core mask的結構體cpu_set_t默認是unsigned long,有128個,可以表示1024個core。正常情況足夠了,如果core大於1024,需要動態申請。具體系統的core數量,通過上面的api獲取。CPU_ALLOCCPU_ALLOC_SIZE中的參數num_cpus必須一致,不然在後續使用中不匹配,導致報錯。

獲取和設置cpu親緣性

#include <sched.h>

int sched_setaffinity(pid_t pid, size_t cpusetsize,
                      cpu_set_t *mask);

int sched_getaffinity(pid_t pid, size_t cpusetsize,
                      cpu_set_t *mask);

如果pid爲0,就表示當前進程。

獲取cpu親緣性

    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    sched_getaffinity(0, sizeof(cpuset), &cpuset);

cpuset中保存了當前進程使用的cpu core。

設置cpu親緣性

    cpu_set_t set;
    CPU_ZERO(&set);
    
    //把core0和core2綁定到當前進程
    CPU_SET(0, &set);
    CPU_SET(2, &set);
    sched_setaffinity(0, sizeof(set), &set);

https://man7.org/linux/man-pages/man2/sched_setaffinity.2.html
https://man7.org/linux/man-pages/man3/CPU_COUNT.3.html
https://linux.die.net/man/3/cpu_set
https://linux.die.net/man/7/cpuset

taskset

除了在代碼中使用libc api設置cpu親緣性,也可以使用taskset進行設置。taskset底層還是調用的libc的api。

       #啓動一個程序,並且綁定到mask指定的core上
       taskset [options] mask command [argument...]
       
       #不加mask,表示獲取pid指定程序的mask;增加mask,表示設置pid指定程序的mask
       taskset [options] -p [mask] pid

       #mask,如果不特殊說明,都是16進制,--cpu-list按照core編號指定,如下都是正確的
       0x00000001
           is processor #0,

       0x00000003
           is processors #0 and #1,

       FFFFFFFF
           is processors #0 through #31,

       0x32
           is processors #1, #4, and #5,

       --cpu-list 0-2,6
           is processors #0, #1, #2, and #6.

       --cpu-list 0-10:2
           is processors #0, #2, #4, #6, #8 and #10. The suffix ":N"
           specifies stride in the range, for example 0-10:3 is
           interpreted as 0,3,6,9 list.

獲取mask

taskset -p 15948
pid 15948's current affinity mask: 2

爲啓動進程設置mask

taskset -c 0 ls

爲指定進程id設置mask

taskset -pc 0,1,2 15948

https://www.man7.org/linux/man-pages/man1/taskset.1.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章