cpu亲缘性
引言
关于cpu亲缘性,文末参考链接讲述的非常详细,本文只记录自己写的一个小demo来了解cpu亲缘性
何为cpu亲缘性
所谓CPU亲缘性可以分为两大类:软亲缘性和硬亲缘性。
- Linux 内核进程调度器天生就具有被称为 CPU 软亲缘性(soft affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。但不代表不会进行小范围的迁移。
- CPU 硬亲缘性是指通过Linux提供的相关CPU亲缘性设置接口,显示的指定某个进程固定的某个处理器上运行。本文所提到的CPU亲缘性主要是指硬亲缘性
使用亲缘性的好处
目前主流的服务器配置都是SMP架构,在SMP的环境下,每个CPU本身自己会有缓存,缓存着进程使用的信息,而进程可能会被kernel调度到其他CPU上(即所谓的core migration),如此,CPU cache命中率就低了。设置CPU亲缘性,程序就会一直在指定的cpu运行,防止进程在多SMP的环境下的core migration,从而避免因切换带来的CPU的L1/L2 cache失效。从而进一步提高应用程序的性能。
Linux CPU亲缘性的使用
利用glibc库中的sched_getaffinity接口,我们获取应用程序当前的cpu亲缘性,而通过sched_setaffinity接口则可以把应用程序绑定到固定的某个或某几cpu上运行
#include <sched.h>
void CPU_ZERO(cpu_set_t *set);
void CPU_CLR(int cpu, cpu_set_t *set);
void CPU_SET(int cpu, cpu_set_t *set);
int CPU_ISSET(int cpu, cpu_set_t *set);
int sched_getaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask);
int sched_setaffinity(pid_t pid, unsigned int cpusetsize, cpu_set_t *mask);
例子
- 使用
htop
命令查看linux操作系统有4个cpu,每一个的负载都很低:
- 我们通过下面的代码,写一个死循环并且亲缘某个CPU来观看是否能把CPU负载利用到100%
注意#define __USE_GNU
的位置,笔者也不知道为啥放在这里可以编译过,不放这里会报undefine的错误
#include <stdio.h>
#define __USE_GNU
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/syscall.h>
void process_affinity(int num) {
// 作用同 : gettid();
pid_t selfpid = syscall(__NR_gettid);
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(selfpid % num, &mask);
// 设置cpu亲缘性
sched_setaffinity(selfpid, sizeof(mask), &mask);
while(1) ; // 死循环
}
int main()
{
// 获取CPU数
int num = sysconf(_SC_NPROCESSORS_CONF);
printf("cpu num = %d\n", num);
pid_t pid;
pid = fork();
if (pid < 0) {
printf("err\n");
return -1;
} else if (pid == 0) {
process_affinity(num); // 子进程,cpu亲缘性
return 0;
}
// 父进程
printf("pid = %d\n", pid);
while (1) sleep(1);
return 0;
}
- 效果
果然,其中一个cpu被死循环的进程亲缘而导致100%了,合理利用cpu亲缘性,可以有效提高cpu负载利用率