将进程/线程与cpu绑定,最直观的好处就是提高了cpu cache的命中率,从而减少内存访问损耗,提高程序的速度。我觉得在NUMA架构下,这个操作对系统运行速度的提升有较大的意义,而在SMP架构下,这个提升可能就比较小。这主要是因为两者对于cache、总线这些资源的分配使用方式不同造成的,NUMA每个cpu有自己的一套资源体系, SMP中每个核心还是需要共享这些资源的,从这个角度来看,NUMA使用cpu绑定时,每个核心可以更专注地处理一件事情,资源体系被充分使用,减少了同步的损耗。SMP由于一部分资源的共享,在进行了绑定操作后,受到的影响还是很大的。
通过linux提供的几个api, 可以轻松地完成这个优化:
- #define _GNU_SOURCE
- #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);
- cpu_set_t
- void CPU_ZERO(cpu_set_t *set);
- void CPU_SET(int cpu, cpu_set_t *set);
- void CPU_CLR(int cpu, cpu_set_t *set);
- int CPU_ISSET(int cpu, cpu_set_t *set);
-
下面是一个实例。
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <unistd.h>
-
- #define __USE_GNU //启用CPU_ZERO等相关的宏
- #include <sched.h>
- #include <pthread.h> //这个东西原来放在__USE_GNU宏之前,结果被编译器报错说CPU_ZERO未定义
-
- void* new_test_thread(void* arg)
- {
- cpu_set_t mask;
- int i = 0;
- int num = sysconf(_SC_NPROCESSORS_CONF);
- pthread_detach(pthread_self());
-
- CPU_ZERO(&mask);
- CPU_SET(1, &mask);
- if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
- {
- printf("set affinity failed..");
- }
- while(1)
- {
- CPU_ZERO(&mask);
- if(sched_getaffinity(0, sizeof(mask), &mask) == -1)
- {
- printf("get failed..\n");
- }
-
- for(i = 0; i < num; i++)
- {
- if(CPU_ISSET(i, &mask))
- printf("new thread %d run on processor %d\n", getpid(), i);
- }
- while(1);
- sleep (1);
- }
- }
- void* child_test_thread(void* arg)
- {
- cpu_set_t mask;
- int i = 0;
- int num = sysconf(_SC_NPROCESSORS_CONF);
- pthread_detach(pthread_self());
-
- while(1)
- {
- CPU_ZERO(&mask);
- if(sched_getaffinity(0, sizeof(mask), &mask) == -1)
- {
- printf("get failed..\n");
- }
-
- for(i = 0; i < num; i++)
- {
- if(CPU_ISSET(i, &mask))
- printf("child thread %d run on processor %d\n", getpid(), i);
- }
- sleep (1);
- }
-
- }
-
- int
- main(int argc, char* argv[])
- {
- int num = sysconf(_SC_NPROCESSORS_CONF);
- int created_thread = 0;
- int myid;
- int i;
- int j = 0;
- pthread_t ptid = 0;
-
- cpu_set_t mask;
- cpu_set_t get;
-
- if(argc != 2)
- {
- printf("usage: ./cpu num\n");
- return -1;
- }
- myid = atoi(argv[1]);
- printf("system has %i processor(s).\n", num);
-
- CPU_ZERO(&mask);
- CPU_SET(myid, &mask);
- if(sched_setaffinity(0, sizeof(mask), &mask) == -1)
- {
- printf("warning: set CPU affinity failed...");
- }
-
- int ret = pthread_create(&ptid, NULL, new_test_thread, NULL);
- if(ret)
- {
- return -1;
- }
- ret = pthread_create(&ptid, NULL, child_test_thread, NULL);
- if(ret)
- {
- return -1;
- }
-
-
- while(1)
- {
- CPU_ZERO(&get);
- if(sched_getaffinity(0, sizeof(get), &get) == -1)
- {
- printf("can‘t get cpu affinity...");
- }
-
- for(i = 0; i < num; i++)
- {
- if(CPU_ISSET(i, &get))
- {
- printf("this process %d is runing on procesor:%d\n", getpid(), i);
- }
- }
-
- sleep(1);
- }
-
- return 0;
- }
编译:
- gcc -o cpu simple_affinity.c -lpthread
执行./cpu [cpu num / masks] ,使用top观察cpu使用状况。 使用./cpu 0 时,可以发现,两颗核心使用率都比较高, 使用./cpu 1时,可以发现,1核的压力比较重。
当然还可以对线程进行cpu绑定。
- #define _GNU_SOURCE
- #include <pthread.h>
-
- 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);
这个介绍了使用的时机,比较经典:http://www.ibm.com/developerworks/cn/linux/l-affinity.html
cpu绑定和cpu亲和性
原文:http://www.cnblogs.com/banwhui/p/4977338.html