进程调度-绑核
1、概述
CPU 亲和性(affinity)就是进程要在某个给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性。这种亲和性分为软亲和性和硬亲和性两种:
软亲和性(affinity): Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。
硬亲和性(affinity):简单来说就是利用linux内核提供给用户的API,强行将进程或者线程绑定到某一个指定的cpu核运行。2.6 版本的 Linux 内核包含的一种机制,它让开发人员可以编程实现硬 CPU 亲和性(affinity)。这意味着应用程序可以显式地指定进程在哪个(或哪些)处理器上运行。
一般来说,Linux内核都可以很好地根据负载情况对进程进行调度,内核包含了一些用来检测任务负载迁移的算法,可以用来进行进程迁移从而均衡CPU负载。一般情况下,进程使用缺省的调度器,当时某些情况下我们需要修改这些缺省行为从而实现特定场景的性能优化,这就是硬亲和性的使用场景:
- 需要进行大量的计算
- 提高Cache命中率
- 对时间敏感的、决定性的进程
2、task_struct
在 Linux 内核中,所有的进程都有一个相关的数据结构,称为 task_struct。有以下几点:
- 在 Linux 操作系统 中 , 进程 作为 调度的实体 , 需要将其抽象为 " 进程控制块 " , 英文全称 " Progress Control Block " , 简称 PCB ;
- 在 Linux 内核 中 , " 进程控制块 " 是通过 task_struct 结构体 进行描述的 ;
- Linux 内核中 , 所有 进程管理相关算法逻辑 , 都是基于 task_struct 结构体的 ;
如果为给定的进程设置了给定的位,那么这个进程就可以在相关的 CPU 上运行。因此,如果一个进程可以在任何 CPU 上运行,并且能够根据需要在处理器之间进行迁移,那么位掩码就全是 1。实际上,这就是 Linux 中进程的缺省状态。
3、设置硬亲和性affinity
3.1 掩码表示
cpu affinity使用位掩码bitmask表示,每一位都表示一个CPU,置1表示“绑定”,最低位表示第一个逻辑CPU、最高位表示最后一个逻辑CPU。典型的CPU affinity表示方式是使用16进制,一个典型的8位CPU:
0x7 = 00000111 //绑定在小核上 0x7f = 01111111 //绑在小核、大核上 0x78 = 01111000 //绑在大核上 0x80 = 10000000 //绑在超核上 0xff = 11111111 //所有核心都可以跑
3.1 用户态进程绑核
(1)函数原型:
//进程绑定和查看CPU的接口 int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
该函数设置进程为pid的这个进程,让它运行在mask所设定的CPU上.如果pid的值为0,则表示指定的是当前进程,使当前进程运行在mask所设定的那些CPU上。第二个参数cpusetsize是mask所指定的数的长度.通常设定为sizeof(cpu_set_t)。如果当前pid所指定的进程此时没有运行在mask所指定的任意一个CPU上,则该指定的进程会从其它CPU上迁移到mask的指定的一个CPU上运行。
int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
该函数获得pid所指示的进程的CPU位掩码,并将该掩码返回到mask所指向的结构中。即获得指定pid当前可以运行在哪些CPU上。同样,如果pid的值为0。也表示的是当前进程。