一、概述
CPU親合力就是指在Linux系統中能夠將一個或多個進程綁定到一個或多個處理器上運行。一個進程的CPU親合力掩碼決定了該進程將在哪個或哪幾個CPU上運行.在一個多處理器系統中,設置CPU親合力的掩碼可能會獲得更好的性能.
進程描述結構體相關成員
struct task_struct { ... int nr_cpus_allowed; //此進程運行的處理器數量 cpumask_t cpus_allowed; //允許的處理器掩碼 ... };
二、用戶空間綁核
1. 方法介紹
一個CPU的親合力掩碼用一個 cpu_set_t 結構體來表示一個CPU集合,下面的幾個宏分別對這個掩碼集進行操作:
CPU_ZERO() //清空一個集合 CPU_SET() //將一個給定的CPU號加到集合,CPU號直接是0 1 2 3 這樣的數字 CPU_CLR() //對將一個給定的CPU號從集合中去掉 CPU_ISSET() //檢查一個CPU號是否在這個集合中.
下面兩個函數就是用來設置獲取線程CPU親和力
#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);
具體使用方法見man的描述,設置進程為pid的這個進程,讓它運行在mask所設定的CPU上.如果pid的值為0,則表示指定的是當前進程,cpusetsize是mask所指定的數的長度,通常設定為sizeof(cpu_set_t).
如果當前pid所指定的進程此時沒有運行在mask所指定的任意一個CPU上,則該指定的進程會從其它CPU上遷移到mask的指定的一個CPU上運行.
成功返回0,失敗返回errno.
2. 例子
創建CPU核數個進程,然后都綁定在CPU2上
#include<stdlib.h> #include<stdio.h> #include<sys/types.h> #include<sys/sysinfo.h> #include<unistd.h> #define __USE_GNU #include<sched.h> #include<ctype.h> #include<string.h> #include<pthread.h> #define THREAD_MAX_NUM 100 //1個CPU內的最多進程數 #define AFFNITY_CURRENT_TASK 0 int cpu_num = 0; //cpu中核數 void * threadFun(void *arg) //arg 傳遞線程標號(自己定義) { int i; cpu_set_t mask; //CPU核的集合 cpu_set_t get; //獲取在集合中的CPU int tid = *(int *)arg; printf("this tid is: %d\n", tid); //顯示是第幾個線程 CPU_ZERO(&mask); //置空 CPU_SET(2, &mask); //設置親和力值,都設置在PU2上。直接設置1 2 3 4 if (sched_setaffinity(AFFNITY_CURRENT_TASK, sizeof(mask), &mask))//設置線程CPU親和力 { printf("sched_setaffinity eror.\n"); return; } CPU_ZERO(&get); if (sched_getaffinity(AFFNITY_CURRENT_TASK, sizeof(get), &get))//獲取線程CPU親和力 { printf("sched_getaffinity eror.\n"); return; } for (i = 0; i < cpu_num; i++) { if (CPU_ISSET(i, &get))//判斷線程與哪個CPU有親和力 { printf("this thread %d is running on processor: %d\n", tid, i); } } return NULL; } int main(int argc, char* argv[]) { int i; int tid[THREAD_MAX_NUM]; pthread_t thread[THREAD_MAX_NUM]; cpu_num = sysconf(_SC_NPROCESSORS_CONF); //獲取核數 printf("system has %i processor(s).\n", cpu_num); for(i = 0; i < cpu_num; i++) { tid[i] = i; //每個線程必須有個tid[i] pthread_create(&thread[i],NULL,threadFun,(void*)&tid[i]); } for(i = 0; i < cpu_num; i++) { pthread_join(thread[i], NULL);//等待所有的線程結束,線程為死循環所以CTRL+C結束 } return 0; }
# gcc cpu_affinity_test.c -lpthread -o affnity_test # ./affnity_test system has 4 processor(s). this tid is: 3 this tid is: 0 this tid is: 1 this tid is: 2 this thread 3 is running on processor: 2 this thread 0 is running on processor: 2 this thread 1 is running on processor: 2 this thread 2 is running on processor: 2
三、內核線程綁核
1. 方法介紹
內核可以使用下面兩個函數設置處理器親和性掩碼
/*kernel/kthread.c*/ void kthread_bind(struct task_struct *p, unsigned int cpu) //綁定時會將進程狀態設置為 TASK_UNINTERRUPTIBLE /*kernel/sched/core.c*/ int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask)
2. 例子
static int rcutorture_booster_init(int cpu) //kernel/rcu/rcutorture.c kthread_bind(boost_tasks[cpu], cpu); wake_up_process(boost_tasks[cpu]); static __init int test_ringbuffer(void) //kernel/trace/ring_buffer.c kthread_bind(rb_threads[cpu], cpu); wake_up_process(rb_threads[cpu]);
四、使用cgroup的cpuset進行綁定
1. 可以綁定一個或一組進程到一個或一組指定的CPU上,使用方法及例子見:https://www.cnblogs.com/hellokitty2/p/14288835.html
五、相關命令
1. # taskset -p <PID> 看PID的CPU親和性
taskset -p 3 pid //表示將進程pid綁定到第3個核上 //-p Set/get the affinity of given PID instead of a new command //-a Set/get the affinity of all threads of the PID
