cpu亲和性

1. 概述

CPU亲和性,是指进程在指定的CPU长时间运行,而尽量不向其他CPU迁移。

在多核CPU的机器上,每个CPU都有自己的缓存,如果进程不显式的绑定CPU,那么有可能在操作系统的调度下,在不同的CPU之间切换,那么原先CPU上的缓存数据就没什么用了,新CPU上的缓存又没有之前的数据,这就造成了缓存命中率降低。如果设置了CPU亲和性,一个进程绑定了CPU之后,那么缓存的命中率就能保持在一个较高的水平,从而提高程序性能,这就是为什么要设置CPU亲和性的原因。另一个好处是提高特定进程调度的优先级,比如一个对实时性要求高的进程做绑定,一方面可以保持它的实时性,另一方面也避免它去干扰其他进程。

2. 相关命令

如下命令可以查看某个进程(线程)运行在哪个CPU上

[root@localhost build]#  ps -eo pid,args,psr | grep ssh
  827 /usr/sbin/sshd -D             1
11436 sshd: root@pts/1              3
11839 grep --color=auto ssh         2
17761 sshd: root@pts/0              3
[root@localhost build]# pstree -p 827
sshd(827)─┬─sshd(11436)───bash(11441)───pstree(11906)
          └─sshd(17761)───bash(17767)───mysql(23070)
[root@localhost build]# ps -To 'pid,lwp,psr,cmd' -p 17761
  PID   LWP PSR CMD
17761 17761   3 sshd: root@pts/0

超线程技术(Hyper-Threading), 把两个逻辑内核(CPU core)模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,常说的的双核四线程/四核八线程指的就是支持超线程技术的CPU.[1] 要注意,超线程技术是通过延迟隐藏的方法,提高了处理器的性能,本质上,就是多个线程共享一个处理单元。因此,采用超线程技术所获得的性能并不是真正意义上的并行。[2]

关联命令,taskset

如下操作可以更改进程对应的CPU

[root@localhost build]# ps -eo pid,args,psr | grep top
12383 top                           3
12387 grep --color=auto top         0
[root@localhost build]# taskset -cp 2 12383
pid 12383's current affinity list: 0-3
pid 12383's new affinity list: 2
[root@localhost build]# ps -eo pid,args,psr | grep top
12383 top                           2
12415 grep --color=auto top         3

主要参数有两个,更多信息可以查看man手册

 -p, --pid
              操作已存在的PID,而不是加载一个新的程序
 -c, --cpu-list
              声明CPU的亲和力使用数字表示而不是用位掩码表示. 例如 0,5,7,9-11.

3. 掩码

下面这一段摘自taskset的man手册,主要讲述CPU亲和性中掩码的作用。

简而言之就是,

CPU关联用位掩码表示,最低阶位对应第一个逻辑CPU,最高阶位对应最后一个逻辑CPU。如果给出了一个无效的掩码,则返回一个错误。

用掩码也可以指定一对多的关系,比如 0x00000003就是绑定0号和1号CPU。.

taskset is used to set or retrieve the CPU affinity of a running process given its PID or to launch a new COMMAND with a given CPU affinity. CPU affinity is a scheduler property that "bonds" a process to a given set of CPUs on the system. The Linux

scheduler will honor the given CPU affinity and the process will not run on any other CPUs. Note that the Linux scheduler also supports natural CPU affinity: the scheduler attempts to keep processes on the same CPU as long as practical for performance

reasons. Therefore, forcing a specific CPU affinity is useful only in certain applications.

The CPU affinity is represented as a bitmask, with the lowest order bit corresponding to the first logical CPU and the highest order bit corresponding to the last logical CPU. Not all CPUs may exist on a given system but a mask may specify more CPUs than

are present. A retrieved mask will reflect only the bits that correspond to CPUs physically on the system. If an invalid mask is given (i.e., one that corresponds to no valid CPUs on the current system) an error is returned. The masks are typically

given in hexadecimal. For example,

0x00000001

is processor #0

0x00000003

is processors #0 and #1

0xFFFFFFFF

is all processors (#0 through #31).

When taskset returns, it is guaranteed that the given program has been scheduled to a legal CPU

4. 编程实例

主要有两个函数API,一个设置,一个获取

  • sched_set_affinity() (用来修改位掩码)
  • sched_get_affinity() (用来查看当前的位掩码)

一个关键数据结构

  • task_struct

修改掩码的宏

void CPU_ZERO (cpu_set_t *set)
这个宏对 CPU 集 set 进行初始化,将其设置为空集。
void CPU_SET (int cpu, cpu_set_t *set)
这个宏将 cpu 加入 CPU 集 set 中。
void CPU_CLR (int cpu, cpu_set_t *set)
这个宏将 cpu 从 CPU 集 set 中删除。
int CPU_ISSET (int cpu, const cpu_set_t *set)
如果 cpu 是 CPU 集 set 的一员,这个宏就返回一个非零值(true),否则就返回零(false)。
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h> /* exit */
#include <unistd.h> /* sysconf */

int main(void) {
    int i, nrcpus;
    cpu_set_t mask;
    unsigned long bitmask = 0;

    // 把0号和1号1CPU加入到mask中
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    CPU_SET(1, &mask);
    // 设置CPU亲和性
    if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_setaffinity");
        exit(EXIT_FAILURE);
    }

    // 获取CPU情和性
    CPU_ZERO(&mask);
    if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) == -1) {
        perror("sched_getaffinity");
        exit(EXIT_FAILURE);
    }

    // 获取逻辑CPU数量
    nrcpus = sysconf(_SC_NPROCESSORS_CONF);
    for (i = 0; i < nrcpus; i++) {
        if (CPU_ISSET(i, &mask)) {
            bitmask |= (unsigned long)0x01 << i;
            printf("processor #%d is set\n", i);
        }
    }

    printf("bitmask = %#lx\n", bitmask);

    exit(EXIT_SUCCESS);
}

outputs

[root@localhost cpu]# gcc affinity.c -o affinity
[root@localhost cpu]# ./affinity 
processor #0 is set
processor #1 is set
bitmask = 0x3

5. 使用场景

  • 需要处理大量计算的任务
  • 测试复杂应用的测试任务
  • 重要、敏感、实时性的任务

参考:

[0] https://zhuanlan.zhihu.com/p/259217757

[1] https://www.cnblogs.com/LubinLew/p/cpu_affinity.html

[2] https://baike.baidu.com/item/%E8%B6%85%E7%BA%BF%E7%A8%8B/86034?fromtitle=%E8%B6%85%E7%BA%BF%E7%A8%8B%E6%8A%80%E6%9C%AF&fromid=276864&fr=aladdin

[3] https://www.ibm.com/developerworks/cn/linux/l-affinity.html

猜你喜欢

转载自blog.csdn.net/niu91/article/details/112601415