将进程与cpu绑定,最直观的好处就是减少cpu之间的cache同步和切换,提高了cpu cache的命中率,提高代码的效率。
从cpu架构上,NUMA拥有独立的本地内存,节点之间可以通过互换模块做连接和信息交互,因此每个CPU可以访问整个系统的内存,但是访问远地内存访问效率大大降低,绑定cpu操作对此类系统运行速度会有较大提升,UMA架构下,多cpu通过系统总线访问存储模块。不难看出,NUMA使用cpu绑定时,每个核心可以更专注地处理一件事情,资源体系被充分使用,减少了同步的损耗。
简单地说,CPU 亲和性(affinity)就是进程要在某个给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性。
软亲和性(affinity): 就是进程要在指定的 CPU 上尽量长时间地运行而不被迁移到其他处理器,Linux 内核进程调度器天生就具有被称为 软 CPU 亲和性(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。
2.6 版本的 Linux 内核还包含了一种机制,它让开发人员可以编程实现硬 CPU 亲和性(affinity)。这意味着应用程序可以显式地指定进程在哪个(或哪些)处理器上运行。
硬亲和性(affinity):简单来说就是利用linux内核提供给用户的API,强行将进程或者线程绑定到某一个指定的cpu核运行。
在 Linux 内核中,所有的进程都有一个相关的数据结构,称为 task_struct 。这个结构非常重要,原因有很多;其中与 亲和性(affinity)相关度最高的是cpus_allowed 位掩码。这个位掩码由n位组成,与系统中的n个逻辑处理器一一对应。 具有 4 个物理 CPU 的系统可以有 4 位。如果这些 CPU 都启用了超线程,那么这个系统就有一个 8 位的位掩码。
如果为给定的进程设置了给定的位,那么这个进程就可以在相关的 CPU 上运行。因此,如果一个进程可以在任何 CPU 上运行,并且能够根据需要在处理器之间进行迁移,那么位掩码就全是 1。实际上,这就是 Linux 中进程的缺省状态。
一般情况下,在应用程序中只需使用缺省的调度器行为。然而,您可能会希望修改这些缺省行为以实现性能的优化。让我们来看一下使用硬亲和性(affinity) 的 3 个原因。
原因 1. 有大量计算要做
基于大量计算的情形通常出现在科学和理论计算中,但是通用领域的计算也可能出现这种情况。一个常见的标志是您发现自己的应用程序要在多处理器的机器上花费大量的计算时间。
原因 2. 提高Cache命中率
在多核运行的机器上,每个CPU都有自己的缓存,缓存着进程使用的信息,而进程可能会被OS调度到其他CPU上,如此一来CPU Cache命中率就低了。当绑定CPU后,程序就会一直在指定的cpu跑,不会由OS调度到其他CPU上,提高CPU Cache命中率。
原因 3. 正在运行时间敏感的、决定性的进程
我们对 CPU 亲和性(affinity)感兴趣的最后一个原因是实时(对时间敏感的)进程。例如,您可能会希望使用硬亲和性(affinity)来指定一个 8 路主机上的某个处理器,而同时允许其他 7 个处理器处理所有普通的系统调度。这种做法确保长时间运行、对时间敏感的应用程序可以得到运行,同时可以允许其他应用程序独占其余的计算资源。
进程设置:
cpu_set_t mask;
/ 初始化set集,将set设置为空/
CPU_ZERO(&mask);
/ 依次将0、1号cpu加入到集合/
CPU_SET(, &mask);
CPU_SET(, &mask);
/将当前进程绑定到cpu /
sched_setaffinity(, sizeof(mask), &mask);
线程设置:
cpu_set_t mask;
/ 初始化set集,将set设置为空/
CPU_ZERO(&mask);
/ 依次将0、1号cpu加入到集合/
CPU_SET(, &mask);
CPU_SET(, &mask);
/将当前线程程绑定到cpu /
pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask);