随手记——SMP系统中亲和性获取和设置

Posted 穿越临界点

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了随手记——SMP系统中亲和性获取和设置相关的知识,希望对你有一定的参考价值。

在学习资料满天飞的大环境下,知识变得非常零散,体系化的知识并不多,这就导致很多人每天都努力学习到感动自己,最终却收效甚微,甚至放弃学习。我的使命就是过滤掉大量的无效信息,将知识体系化,以短平快的方式直达问题本质,把大家从大海捞针的痛苦中解脱出来。

1 什么是亲和性

亲和性简单理解就是某一个线程或中断和哪个处理器核亲近。和哪个(一个或多个)核亲近,就在占用哪个核的资源,除非这个核被关闭了。

系统默认的亲和性就是对所有核无差别对待,一个线程可以负载分担到任何核上。

2 为什么要设置亲和性

系统默认的所有线程和中断的亲和性是会根据负载,均匀分担到各个核上的。所以,会存在经常动态调整绑核关系的情况。因为核迁移过程是需要时间的,也会影响Cache命中率,经常进行核迁移会影响系统性能。

系统的使用者由于对业务比较熟悉,所以可以选择将指定的线程绑定在指定的处理器核心上,以提高系统的效率和稳定性。此外,定位问题也比较直观一些。

3 设置线程亲和性

3.1 在shell中设置亲和性

在shell中设置亲和性的指令是 taskset 。该指令可以将指定线程迁移到指定的CPU核心(簇)上。

# 设置亲和性
指令名称 选项	CPU核心列表	线程ID
taskset -pc 0,1-3,5 PID

# 获取亲和性
taskset -p PID

3.2 在C语言中设置亲和性

在C语言中设置亲和性的接口有3组,如下表所示。

接口功能说明
int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);设置进程或线程(轻量级进程)亲和性pid填0就是本进程;pid填syscall(SYS_gettid)就是轻量级进程。
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);获取进程或线程(轻量级进程)亲和性同上
int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);设置线程亲和性和上述接口对比主要是第一个入参类型不同。
int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);获取线程亲和性同上
int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);设置线程亲和性用在创建线程之前,和上述接口的主要区别也是第一个参数。
int pthread_attr_getaffinity_np(pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);获取线程亲和性同上

下面,只对第一组接口给出使用示例。其他接口的用法大同小异,遇到之后查询一下man手册就可以了。

  1 #define _GNU_SOURCE
  2 #include <stdio.h>
  3 #include <unistd.h>
  4 #include <sched.h>
  5 #include <sys/syscall.h>
  6
  7
  8 /* Get thread affinity */
  9 int get_thread_affinity()
 10 
 11         pid_t tid;
 12         cpu_set_t mask;
 13         int cpu_num = 0;
 14         int i = 0;
 15
 16         tid = syscall(SYS_gettid); //or use syscall(__NR_gettid)
 17         CPU_ZERO(&mask);
 18
 19         if (sched_getaffinity(tid, sizeof(cpu_set_t), &mask)) 
 20                 perror("");
 21                 return -1;
 22         
 23         cpu_num = sysconf(_SC_NPROCESSORS_CONF);
 24         for (i = 0; i < cpu_num; i++) 
 25                 if (CPU_ISSET(i, &mask))
 26                         printf("The %d cpu is set.\\n", i);
 27         
 28
 29         return 0;
 30 
 31 /* Set thread affinity */
 32 int set_thread_affinity(int cpu_no)
 33 
 34         pid_t tid;
 35         cpu_set_t mask;
 36
 37         tid = syscall(SYS_gettid);
 38         CPU_ZERO(&mask);
 39         CPU_SET(cpu_no, &mask);
 40
 41         if (sched_setaffinity(tid, sizeof(cpu_set_t), &mask)) 
 42                 perror("");
 43                 return -1;
 44         
 45
 46         return 0;
 47 
 48
 49 int main(int argc, char* argv[])
 50 
 51         (void)get_thread_affinity();
 52         (void)set_thread_affinity(3);
 53         printf("------------------after set affinity---------------------\\n");
 54         (void)get_thread_affinity();
 55
 56
 57         return 0;
 58                                        

4 设置中断的亲和性

设置和获取中断亲和性可以借助proc系统。设置就是往文件中写,获取直接读取文件即可。

# 例如将中断号8的亲和性设置为第0-3个核上
# 掩码形式
echo f > /proc/irq/8/smp_affinity
# 列表形式
echo 0-3 > /proc/irq/8/smp_affinity_list

恭喜你又坚持看完了一篇博客,又进步了一点点!如果感觉还不错就点个赞再走吧,你的点赞和关注将是我持续输出的哒哒哒动力~~

以上是关于随手记——SMP系统中亲和性获取和设置的主要内容,如果未能解决你的问题,请参考以下文章

Linux 编程之进程篇:调度优先级亲和性和资源限制

Linux 编程之进程篇:调度优先级亲和性和资源限制

Linux 编程之进程篇:调度优先级亲和性和资源限制

从 C/C++ 设置进程优先级和 irq 进程的亲和性

多队列网卡介绍

K8S调度之pod亲和性