• 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)上,把其他进程绑定到其他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 .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 
    
           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,需要动态申请。CPU_ALLOCCPU_ALLOC_SIZE中的参数num_cpus必须一致,不然在后续使用中不匹配,导致报错。

    获取和设置cpu亲缘性

    #include 
    
    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

  • 相关阅读:
    练[SUCTF 2019]CheckIn
    树的基本术语
    VMware+Ubuntu安装过程,含秘钥
    基于单片机的智能蓝牙避障循迹小车
    能否在 vpp 外部释放 vpp 创建的 vlib buffer?
    vulnhub digitalworld.local: DEVELOPMENT
    /usr/bin/c++ not found 处理
    经典匹配算法: KMP、Sunday与ShiftAnd
    python车辆故障管理系统的设计与实现flask-django-nodejs-php
    【【萌新的FPGA学习之同步FIFO的代码与tb】】
  • 原文地址:https://www.cnblogs.com/studywithallofyou/p/17622860.html